java 设计模式 -- 观察者模式

383 阅读3分钟

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

1.观察者模式的理解

观察者模式适用于多个对象之间存在一对多的关系时,当其中一个对象的行为状态发生改变时,所依赖的其它对象会受到通知,也称发布-定义模式。观察者模式属于一种行为型模式。

比如我们在日常生活中,看到红灯会停,看到绿灯会通过,又或者我们看天气预报,预报明天下雨,我们回到这个信息,可能会带雨伞,预报明天晴天,我们就不带雨伞。

2.原理

2.1 组成

观察者模式的主要角色如下:

  1. 抽象主题(Subject)角色:它是一个接口或者抽象类,即抽象被观察的类,它提供增加、删除 以及通知所有观察者的抽象方法。
  2. 具体主题(Concrete Subject)角色:也叫具体目标类,具体被观察的类,它提供了一个用于保存观察者对象的聚集类(通常时list 集合),它实现抽象目标中的通知方法,当它自身的内部状态发生改变时,就会调用通知方法,通知所有注册过的观察者对象。
  3. 抽象观察者(Observer)角色:它是一个接口或者抽象类,它包含了一个抽象的关联方法,当接到具体主题的更改通知时被调用。
  4. 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,当观察到具体目标的内部状态发生改变时,就会调用该回调方法。

2.2 类图

本类图 以天气数据作为主题,各网站观测到天气数据更新会把数据同步到自己的网站,以各网站作为 观察者,类图如下:

图片.png

3.代码

3.1 抽象主题

public interface Subject {
   // 注册观察者
   public void registerObserver(Observer o);
   // 移除观察者
   public void removeObserver(Observer o);
   // 通知所有的观察者
   public void notifyObservers();
}

3.2 具体主题

图片.png 图片.png

3.3 抽象观察者

public interface Observer {
    // 接收到通知时的被调用方法
   public void update(float temperature, float pressure, float humidity);
}

3.4 具体观察者

具体观察者1:

图片.png 具体观察者2:

图片.png

3.5 调用程序

图片.png

输出结果:

图片.png

4.总结

观察者模式的优点:

  • 观察者模式对观察者的管理通常是以集合的方式,当我们新增一个具体观察者时,只需要继承抽象观察者即可,无需修改原来的代码,符合ocp原则
  • 目标和观察之间建立了一套触发机制

观察者模式的缺点:

  • 如果一个目标有很多观察者的话,将它们每个都通知到 会比较耗费事件。
  • 观察者模式可能会出现循环引用的情况,导致系统崩溃 (java 提供了观察模式支持的类: java.util.Observer)

5.源码应用

5.1 jdk中

java.util.Observer : 抽象观察者

public interface Observer {
   //当观察的对象状态更改时,会调用这个方法
   void update(Observable o, Object arg);
}

java.util.Observable: 具体主题

这里只贴出部分重要代码,大家感兴趣的话,可以自己点进源码查看

public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;

    public Observable() {
        obs = new Vector<>();
    }

    // 添加一个观察者
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    // 移除一个观察者
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    //通知所有观察者
    public void notifyObservers() {
        notifyObservers(null);
    }

    //通知所有观察者 具体实现
    public void notifyObservers(Object arg) {
        Object[] arrLocal;

        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

    // 清空所有观察者
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }
}