概念
观察者模式定义了对象之间的一对多依赖, 这样一来, 当一个对象改变状态时, 它的所有依赖者都会受到通知并自动更新.
代表人物: MVC
适用场景
1. 当一个对象的改变需要同时改变其他对象的, 或者要通知其他对象
2. 当一个抽象模型有两个方面, 其中一个方面依赖于另一个方面, 应该将这两者封装成独立的对象, 使它们可以各自独立的改变和复用
在以下任一情况下可以使用观察者模式:
结构
主题(Subject)
被观察者, 可以有任意多个观察者, 提供注册和删除观察者的接口
观察者(Observer)
为那些在目标发生改变时需获得通知的对象定义一个更新接口。当它的状态发生改变时, 向它的各个观察者发出通知
具体主题(ConcreteSubject) 提供自己的getState/setState类似函数, 将具体数据存入观察者或供观察者获取
具体观察者(ConcreteObserver)维护一个指向ConcreteSubject的引用或指针, 与感兴趣的数据与具体主题保持一致
两种实现方式:
推送(push)方式: 当主题变化时, 主动将数据发送给观察者
拉取(pull)方式: 当主题变化时, 仅仅告诉观察者数据发生变化, 让观察者自己去获取感兴趣的数据
push方式是每次将观察者所需要的数据全部推送过去, 这样做的缺点一是推送给观察者的数据可能包含观察者并不感兴趣的冗余数据,二是当主题扩展功能时,新增更多的状态,可能导致观察者的接口发生变化, 同时主题需要修改和更新对每位观察者的调用. 因此pull方式更为灵活
优缺点
优点:
观察者模式提供了一种对象设计, 让主题和观察者之间松耦合.
当两个对象之间松耦合, 它们依然可以交互, 但是不太清楚彼此的细节.
松耦合的设计之所以能让我们建立有弹性的OO系统, 能够应对变化, 是因为对象之间的互相依赖降到了最低.
缺点:
如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
意外的更新 因为一个观察者并不知道其它观察者的存在 , 它可能对改变目标的最终代价一无所知。在目标上一个看似无害的的操作可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。此外 , 如果依赖准则的定义或维护不当,常常会引起错误的更新 , 这种错误通常很难捕捉。
如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
意外的更新 因为一个观察者并不知道其它观察者的存在 , 它可能对改变目标的最终代价一无所知。在目标上一个看似无害的的操作可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。此外 , 如果依赖准则的定义或维护不当,常常会引起错误的更新 , 这种错误通常很难捕捉。
例子
参考一般的事件循环的系统, 代码后面补充