观察者模式
模式定义
观察者模式,也叫订阅/发布(Publish/Subscribe)模式、源/监听器(Source/Listener)模式。该模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。观察者模式在GOF95中分类为行为模式。
模式结构与说明
- Subject:主题(目标)接口,主题可以注册、移除对其感兴趣的观察者,在自身数据发生变化的时候,还可以通知这些观察者。一个主题可以有多个观察者,需要注意的是,观察者的顺序应当是无关紧要的。主题也被称为“被观察者”(Observable)
- 所有的观察者必须实现Observer接口,以便主题状态发生变化时,可以被通知
观察者模式是一种广泛使用、非常重要的设计模式,它有利于降低对象间的耦合,同时让对象保持高度协作。该模式的松耦合特性体现在:
- 关于观察者的一切,主题只知道它实现了观察者接口,其它一概不知
- 在任何时候,主题的观察者可以被动态的添加、删除
- 当新类型的观察者出现时,主题的代码不需要进行修改
- 修改主题或者观察者的任一方,对方不会受到影响
观察者模式的实现有两种方式:
- 推模型:目标主动向观察者推送所有需要的信息,不管观察者是否需要
- 拉模型:模板在通知观察者时,仅传递少量的信息。如果观察者需要具体的信息,则需要自行到目标中拉取
应用举例
考虑一个股票信息推送的需求,当股票价格发生变化的时候,交易所大屏幕、电脑客户端,甚至是手机短信都需要得到通知,这样的场景使用通过观察者模式实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
//股票主题 function StockSubject() { this.stockData = 0; this.observers = []; } StockSubject.prototype.registerObserver = function( observer ) { this.observers.push( observeer ); } StockSubject.prototype.notifyObservers = function() { for ( var i = 0; i < this.observers.length; i++ ) { this.observers[i].update( this.stockData ); } } //观察者接口 function Observer() {} Observer.prototype.update = function( data ) {} //手机短信观察者 function SMSObserver() {} SMSObserver.prototype = new Observer(); SMSObserver.prototype.update = function( data ) { console.log( 'You got a message: ' + data ); } |
经典应用
Java内置观察者模式
从JDK 1.0开始,内置的API就提供了观察者模式:
任何Observable的子类都可以作为主题,还实现Observer接口即可成为观察者。Java内置观察者模式的工作方式如下:
- 调用 setChanged() ,标记主题变化这个事实
- 调用 notifyObservers() 或者 notifyObservers(Object arg) ,用来通知观察者,其中arg用于向观察者传递数据
- 观察者的 update(Observable o, Object arg) 被调用,其中arg就是上一步方法中的参数
除了上述通用观察者模式之外,Java中的Swing、JavaBeans、RMI等组件都使用了观察者模式来实现。
Spring事件系统
Spring框架集成了一个成熟的观察者模式实现,这就是Spring的事件系统,其核心接口和类如下图:
- ApplicationListener接口就是Observer角色,值得注意的是,Spring使用泛型技术定义了此接口,因此允许一个观察者只关注目标的某种变化,即某种事件
- ApplicationEventMulticaster接口相当于Subject角色(的代理),我们常用其缺省实现 SimpleApplicationEventMulticaster 。可以看到,该接口能够增删观察者,这正是Subject角色的职能
- ApplicationEvent类,事件,用来表示Subject的某种变化,在这样的变化发生时,用来承载需要从Subject传递给Observer的数据
将需要在Subject和Observer之间传递的数据抽象为Event,是事件系统的通用技巧。
ExtJS事件系统
在ExtJS中事件机制被广泛的使用,不但各种UI组件,数据处理等基础包也支持事件机制。内置的观察者模式是ExtJS事件系统的基础:
- Ext.util.Observable即主题(目标),这是一个混入类(Mixins),在ExtJS中很多组件均混入了该类型。Observable可以添加、删除观察者,在事件发生时通知观察者,并可以注册其自身支持的事件类型,以及发布这些事件。fire方法用于发布事件,其传入的arg...参数,会被观察者接收到
- 由于Java语言中函数是first-class对象,因此观察者角色就是各种规格的函数,这些函数在事件发生时自动回调,传入由fireEvent()提供的arg...参数
Leave a Reply