这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战
概述
观察者模式(Observer Pattern)定义对象之间的一种一对多的依赖关系,使得当一个对象发生变化时,其相应依赖对象皆能得到通知并被自动更新。又称为发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式,是一种对象行为型模式。
在观察者模式中,发生改变的对象称为观察目标,被通知的对象称为观察者。一个观察目标可以对应多个观察者,并且这些观察者之间可以没有任何联系,可以根据需要增加和删除观察者。
结构
- Subject(目标):被观察的对象,又称为主题,一般是接口或抽象类,但也可以是具体类,其中定义了一个观察者集合。一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法。
- ConcreteSubject(具体目标):当它的状态发生改变时,会向它的各个观察者发出通知。
- Observer(观察者):一般为接口,其中定义了更新数据的方法。
- ConcreteObserver(具体观察者):真正实现了更新数据的方法,在该方法中会将自己添加到目标集合中或从目标集合中删除。
优点
- 观察者和被观察者是抽象耦合,被观察者并不认识任何一个具体观察者,符合迪米特法则。
- 观察者和被观察者之间可以独立变化,符合开闭原则。
- 观察者模式支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。
缺点
- 如果一个被观察者对象有很多的直接和间接的观察者的话,通知观察者会花费大量的时间。
- 如果在被观察者之间有循环依赖的话,会导致系统崩溃。
- 一个被观察者,多个观察者,消息的通知是顺序进行的,一个观察者的问题会影响到系统的整体执行效率。
- 观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
- 如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
应用场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,但它们可以各自独立地改变和复用。
- 事件多级触发场景。
- 跨系统的消息交换场景。
JDK 中的应用场景
在 JDK 中 java.util.Observable 就是观察者模式中的观察目标;java.util.Observer 是观察者模式中的观察者。
public class Observable {
private Vector<Observer> obs;
public void notifyObservers(Object arg) {
...
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
}
public interface Observer {
void update(Observable o, Object arg);
}