设计模式 Observer

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

Dependents, Publish-Subscribe

将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一致性。

适用性:

  • 当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。
  • 当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。

结构

Subject

  • Subject知道它的Observer。可以有任意多个Observer观察同一个Subject。
  • 提供注册和删除Observer对象的接口。

Observer

  • 为那些在Subject发生改变时需获得通知的对象定义一个更新接口。

ConcreteSubject

  • 将有关状态存入各ConcreteObserver对象。
  • 当它的状态发生改变时, 向它的各个Observer发出通知。

ConcreteObserver

  • 维护一个指向ConcreteSubject对象的引用。
  • 存储有关状态,这些状态应与Subject的状态保持一致。
  • 实现Observer的更新接口以使自身状态与目标的状态保持一致。

允许你独立的改变Subject和Observer。

优缺点:

  • V Subject和Observer间的抽象耦合
  • V 支持广播通信
  • X 意外的更新

1. 创建Subject到其Observer之间的映射

最简单的方法:显式地在Subject中保存对Observer的引用

时间换空间:用一个关联查找机制(如hash表)来维护Subject到Observer的映射

2. 观察多个Subject

必须扩展Update接口以使Observer知道是哪一个Subject送来的通知

Subject对象可以简单地将自己作为Update操作的一个参数

3. 谁触发更新

A 由Subject对象的状态设定操作在改变Subject对象的状态后自动调用Notify

B 让用户负责在适当的时候调用Notify

4. 对已删除Subject的悬挂引用

当一个Subject被删除时,让它通知它的Observer将对该Subject的引用复位

5. 在发出通知前确保Subject的状态自身是一致的

抽象的Subject类中的模板方法发送通知:定义那些子类可以重定义的原语操作, 并将Notify作为模板方法中的最后一个操作

6. 避免特定于Observer的更新协议—推/拉模型

推(Push)模型:Subject向Observer发送关于改变的详细信息, 而不管它们需要与否

拉(Pull)模型:Subject除最小通知外什么也不送出,而在此之后由Observer显式地向Subject询问细节

7. 显式地指定感兴趣的改变

扩展Subject的注册接口,让各Observer注册为仅对特定事件感兴趣,以提高更新的效率

Aspect:

void Subject::Attach(Observer*, Aspect& interest);

void Observer::Update(Subject*, Aspect& interest);

8. 封装复杂的更新语义

当目标和观察者间的依赖关系特别复杂时, 可能需要一个维护这些关系的对象,即更改管理器(ChangeManager)

目的是尽量减少Observer反映其Subject的状态变化所需的工作量

责任:

  • 将一个Subject映射到它的Observer并提供一个接口来维护这个映射
  • 定义一个特定的更新策略
  • 根据一个Subject的请求, 更新所有依赖于这个Subject的Observer

9. 结合Subject类和Observer类

用不支持多重继承的语言书写的类库通常不单独定义Subject和Observer类, 而是将它们的接口结合到一个类中

原文地址:https://www.cnblogs.com/chenkkkabc/p/3132597.html