观察者模式
观察者模式
对象行为型模式

模式动机
在软件系统中,可能有一些事件驱动的设计。比如在一个气象系统中,有一个Weather对象,可以获取天气状况;该系统希望设计几种公告板,显示不同的天气状况,公告板需要实时更新,即随着Weather对象的天气属性更新而更新。这时候就需要利用观察者模式来监听数据的更新,实时更新公告板。同时要考虑到扩展性,随时增加新的公告板 / 让开发者自己设计。

观察者模式期望建立一种对象与对象之间的依赖关系,一个对象发生改变时自动通知其他对象。发生改变的对象称为观察目标,被通知的对象称为观察者,一个观察目标可以对应多个观察者,而观察者之间没有联系,可以按需添加或删除观察者,增加系统可扩展性。
分析
- 观察者模式的核心是如何建立对象与对象间的依赖关系
- 关键对象是观察目标和观察者,一个目标可以有任意数目与之依赖的观察者,一旦目标状态改变,所有观察者都被通知
作为对通知的响应,每个观察者及时更新自己的状态以合目标的状态同步,因此观察者模式也叫发布-订阅模式
松耦合
松耦合指两个对象彼此之间存在交互,但是不清楚彼此的实现细节(即面向对方暴露的接口编程),只要松耦合双方的接口仍被遵守,即使改变任意一方的实现也不会影响另一方,即可以自由地改变。
观察者模式的观察目标和观察者之间是松耦合关系。
实例:WeatherData

部分典型代码如下:
public interface Subject { |
优点
- 可以实现表示层和数据逻辑层的分离,且定义稳定的消息更新传递机制,抽象了更新接口,各种表示层都可以作为观察者(实现抽象观察者的update即可)
- 观察目标和观察者之间是松耦合(抽象耦合,只耦合接口)
- 支持广播
- 符合开闭原则
缺点
- 如果观察目标有很多直接或间接观察者,那么通知到所有观察者会耗费很多时间
- 如果观察者和观察目标之间不小心引入了循环依赖,那么观察目标会触发循环调用,导致系统崩溃
- 观察者永远无法知道观察目标是怎么变化的,只知道变了
适用场合
- 一个对象的改变会导致其他对象的改变,但不知道具体有多少对象改变,使用观察者模式可以降低这些对象之间的耦合度
- 一个对象必须通知其他对象,但并不知道这些对象是谁
模式扩展
Java观察者模式
Java提供对观察者模式的支持,在java,util
包中提供了Observable类和Observer接口以支持观察者模式

setChanged() { |
通知机制——谁来触发更新?
目标和观察者依赖通知机制来保持一致,但是谁来调用notify触发更新呢?有下面两个选择,各有利弊:
- 目标对象的状态设定操作在改变目标状态后自动调用notify,优点是客户端没有记忆负担,不需要记住在目标对象上调用notify;缺点是连续set操作会触发多次更新,效率低
- 客户负责在适当的时候调用notify,优点是可以在一系列set之后一次性触发更新,批处理的效率更高;缺点是客户可能忘记,出错率较高
因此当目标和观察者之间的依赖关系比较复杂时,需要引入一个专门维护依赖关系的对象,称为ChangeManager
其目标是观察目标状态变化触发观察者更新所需的工作量。比如如果一个更新操作涉及几个相互依赖的观察目标都变化,那么cm会保证仅在所有目标都更新完毕后才通知它们的观察者,而不是每个目标都通知。
ChangeManager

MVC模式
MVC 模式是一种架构模式,它包含三个角色: 模型(Model),视图 (View)和控制器 (Controller)。观察者模式可以用来实现 MVC 模式,观察者模式中的观察目标就是 MVC 模式中的 模型 (Model),而观察者就是 MVC 中的视图 (View),控制器 (Controller)充当两者之间的中介者(Mediator)。当模型层的数据发生改变时,视图层将自动改变其显示内容。

(•‿•)