观察者模式(让对象能够在状态改变时被通知)

源码地址 https://github.com/DingMouRen/DesignPattern
观察者模式(让对象能够在状态改变时被通知)_第1张图片
观察者模式.png
  • Subject(目标,也就是Observable可观察者)可以有任意多的观察者观察它,同时提供注册和删除观察者对象的接口
  • Observer(观察者)定义一个更新接口
  • ConcreteSubject(具体目标)将有关状态存入各ConcreteObserver对象,当它状态发生变化时,向它的各个具体观察者发出通知。
  • ConcreteObserver(具体观察者)维护这一个指向ConcreteSubject的引用;存储着有关 状态,这些状态与具体目标的状态保持一致;实现了Observer的更新接口来使自身状态与具体目标的状态保持一致。
定义

观察者模式定义了对象间一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。

使用场景
  • 当对一个对象的改变需要同时改变其他对象,而又不知道具体有多少对象有待改变时
  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之 , 你不希望这些对象是紧密耦合的
协作
  • 当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者。
  • 在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息来使它的状态与目标对象的状态一致。
举个例子

我们有一个对象ConcreteSubject,可以获取到环境中的温度、湿度和压力,也就是被观察者(目标),这里有两个对象ConcreteObserver系列,用途是显示环境中的温度、湿度和压力,我们要求在ConcreteSubject的数据发生变化时,ConcreteObserver系列的要同时更新数据。


//目标接口:1.定义注册接口  2.定义注销接口 3.定义发送通知的接口
public interface Subject {
    void registerObserver(Observer observer);//注册观察者
    void removeObserver(Observer observer);//注销观察者
    void notifyObservers();//目标状态变化时,调用这个方法通知所有观察者
    void notifyObservers(Object arg);//也可以通知所有的观察者,另外可以携带其他的数据
}

//具体目标:1.存储最新的状态数据 2.维护着所有观察者的集合 3.一旦数据更新,向所有观察者发送通知
public class ConcreteSubject implements Subject {
    private ArrayList observers;//存储注册的观察者对象,ArrayList是线程不安全的,Vector是线程安全的
    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//压力

    public ConcreteSubject() {
        this.observers = new ArrayList();
    }

    @Override
    public void registerObserver(Observer observer) {
        if (observer == null) throw  new NullPointerException();
        if (!observers.contains(observer)) observers.add(observer);//判断是否有这个观察者,不然会被通知两回
    }

    @Override
    public void removeObserver(Observer observer) {
        int index = observers.indexOf(observer);
        if (index >= 0) observers.remove(index);
    }

    @Override
    public void notifyObservers() {
       notifyObservers(null);
    }

    @Override
    public void notifyObservers(Object arg) {
        for(Observer observer : observers){
            observer.update(this,arg);
        }
    }

    public void setNewData(float temperature,float humidity,float pressure){
        this.temperature =temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

    private void measurementsChanged(){
        notifyObservers();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
}
//观察者接口
public interface Observer {
    void update(Subject subject,Object arg);
}
//用来显示最新的数据的接口
public interface DisplayNewData {
    void display();
}
//具体观察者:1.维护着一个目标的引用  2.实现观察者接口,更新状态与目标状态一致
public class ConcreteObserver_1 implements Observer,DisplayNewData {
    private Subject subject;
    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//压力

    public ConcreteObserver_1(Subject subject) {//传入目标subject用来注册观察者,自然也可以删除观察者
        this.subject = subject;
        this.subject.registerObserver(this);
    }

    /**
     * 这里获取的更新数据的方式是“拉”,我们想要什么数据,就通过get方法获得,而不是目标把数据主动推给观察者的
     * @param subject
     * @param arg
     */
    @Override
    public void update(Subject subject, Object arg) {
        ConcreteSubject concreteSubject = (ConcreteSubject) subject;
        this.temperature = concreteSubject.getTemperature();
        this.humidity = concreteSubject.getHumidity();
        this.pressure = concreteSubject.getPressure();
        display();
    }

    @Override
    public void display() {
        System.out.println(this.getClass().getSimpleName()+"最新的数据:\n温度:"+temperature+"℃ 湿度:"+humidity+"% 压力:"+pressure);
    }
}

使用

 public static void main(String[] args) {
        //创建目标,可观察者
        ConcreteSubject concreteSubject = new ConcreteSubject();
        //创建观察者并注册
        ConcreteObserver_1 observer_1 = new ConcreteObserver_1(concreteSubject);
        ConcreteObserver_2 observer_2 = new ConcreteObserver_2(concreteSubject);
        //更新数据
        concreteSubject.setNewData(1,2,3);
    }

java中的java.util.Observable的缺点:

  • 我们想同时具有Observable类和另一个超类的行为时,就会陷入困难,java是不支持多重继承的,限制了Observable的复用潜力
  • Observable中的setChanged()被protected修饰的,只能通过继承,违反OO设计原则:多用组合,少用继承
总结

优点

  • 观察者与被观者之间是抽象耦合,可以应对业务变化
  • 增强系统灵活性,更易扩展
    缺点
  • 一个观察者卡顿,会影响整体的执行效率,在这种情况下,可以采用异步的方式。

你可能感兴趣的:(观察者模式(让对象能够在状态改变时被通知))