1 定义
观察者模式(Observer Pattern)定义了一种一对多的依赖对象关系,使得当那一个对象状态发生改变时,依赖它的多个对象均能得到通知并自动更新(做出相应反应)。
发生状态变化的对象叫观察目标(Subject
),依赖它的多个对象叫观察者(Observers
)。subject
通知其observer
的方式,通常以主动调用observer
的特定方法进行。
这意味着,在subject
中存在一个注册列表(Registered list),记录了当自己状态发生变化时,需要调用的每个observer
对应的特定方法。
观察者模式的核心思想,与发布-订阅模式(Publish/Subscribe Pattern)
非常类似的,即通过引入一个**事件通知(Event Notification)**机制将事件两端的对象(事件发生对象和关注该事件发生的对象)实现解耦。
而两者的区别在于:
-
耦合关系不同
- 在观察者模式中,
Subject
松耦合于Abstract Observer
; - 而发布-订阅模式可以看做是观察者模式的一种变种。通过引入Broker层,作为
Subject
与Observer
之间的中间层,最终Subject
与Observer
之间不存在任何耦合
- 在观察者模式中,
-
讨论的上下文所处的粒度不同
- 观察者模式往往在一个代码实现的上下文去讨论的(Design Pattern),即programming language specific;
- 而发布-订阅模式既可以在一个代码实现的上下文去讨论(Design Pattern),也可以从架构设计的角度讨论。这时,发布-订阅模式更多是一个架构模式(Architectural Pattern)。比如**面向消息的中间件系统(message-oriented middleware system,MOMS)**则是从架构层面实现了发布-订阅模式的一个典型例子,典型的面向消息的中间件系统包括JMS(Java Message Service)、ActiveMQ
-
同异步的实现不同
- 观察者模式往往以同步的方式实现,即当特定事件发生时,观察者(Observer)的事件处理方法被依次同步调用
- 发布-订阅模式往往以异步的方式实现。当特定事件发生(比如,一个特定的Topic)时,发布者(Publisher)通知消息队列(Message Queue)或Broker对象,此后通知结束。此后,订阅者再去消费这个事件。
2 特点
- 一个
subject
可以对应多个observer
,这些observer
之间可以没有任何关系(耦合)。 subject
松依赖(松耦合)于observer
,而observer
不依赖于subject
。- 同时也可以根据需要随意地向
subject
增加或删除observer
,这意味着系统非常易于扩展。
在应用观察者模式的过程中,通常包括三个行为:
- 添加(Attach):将一个
observer
添加到subject
中的注册列表(Registered list)中。这意味着当特定事件发生时,这个observer
总能收到通知 - 移除(Detach):将一个已经存在的
observer
从subject
中的注册列表(Registered list)中移除。这意味着当被移除之后,特定事件发生时,这个observer
也不会收到通知 - 通知(Notify):
subject
调用observer
提供的通知更新函数以告知observer
此时事件发生
3 示例
// TODO
4 优点
- 观察者模式符合“开闭原则”(Open/Closed Principle)
- 观察者模式可用于广播通信
- 观察者模式在
subject
和observer
之间建立了一个抽象的耦合 - 使用观察者模式可以实现表现层和逻辑层的分离
5 缺点
- 如果在
Observer
和subject
之间有循环依赖时,可能会导致触发无限通知调用,进而导致系统崩溃
6 Note
6.1 Java的支持
在JDK的java.util包中,提供了Observable类以及Observer接口,它们构成了Java语言对观察者模式的支持。
6.2 观察者模式在MVC中的应用
在常用的MVC (Model - View - Controller)架构模式中也应用了观察者模式。MVC中包含三个角色:模型(Model)、视图(View)和控制器(Controller)。
其中 Model
对应于观察者模式中的 subject
,而View
对应于观察者模式中的observer
。
当Model层中的特定事件发生(如数据发生改变)时,View层将收到通知(并更新显示的数据),
7 Reference
- Observer pattern
- 观察者模式
- Apple Cocoa - Model-View-Controller
- http://developers-club.com/posts/270339/
- https://medium.com/@huytrongnguyen1985/from-pub-sub-pattern-to-observer-pattern-f4ae1e425cc9
- http://developers-club.com/posts/270339/
- https://hackernoon.com/observer-vs-pub-sub-pattern-50d3b27f838c