「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」
1.观察者模式的理解
观察者模式适用于多个对象之间存在一对多的关系时,当其中一个对象的行为状态发生改变时,所依赖的其它对象会受到通知,也称发布-定义模式。观察者模式属于一种行为型模式。
比如我们在日常生活中,看到红灯会停,看到绿灯会通过,又或者我们看天气预报,预报明天下雨,我们回到这个信息,可能会带雨伞,预报明天晴天,我们就不带雨伞。
2.原理
2.1 组成
观察者模式的主要角色如下:
- 抽象主题(Subject)角色:它是一个接口或者抽象类,即抽象被观察的类,它提供增加、删除 以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject)角色:也叫具体目标类,具体被观察的类,它提供了一个用于保存观察者对象的聚集类(通常时list 集合),它实现抽象目标中的通知方法,当它自身的内部状态发生改变时,就会调用通知方法,通知所有注册过的观察者对象。
- 抽象观察者(Observer)角色:它是一个接口或者抽象类,它包含了一个抽象的关联方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,当观察到具体目标的内部状态发生改变时,就会调用该回调方法。
2.2 类图
本类图 以天气数据作为主题,各网站观测到天气数据更新会把数据同步到自己的网站,以各网站作为 观察者,类图如下:
3.代码
3.1 抽象主题
public interface Subject {
// 注册观察者
public void registerObserver(Observer o);
// 移除观察者
public void removeObserver(Observer o);
// 通知所有的观察者
public void notifyObservers();
}
3.2 具体主题
3.3 抽象观察者
public interface Observer {
// 接收到通知时的被调用方法
public void update(float temperature, float pressure, float humidity);
}
3.4 具体观察者
具体观察者1:
具体观察者2:
3.5 调用程序
输出结果:
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();
}
}