定义
观察者设计模式也叫做发布-订阅(Publish-Subscribe)模式。有点像杂志订阅的意思,你向杂志社订阅杂志,然后提供了自己的姓名和邮箱地址,这样杂志社就可以把你所订阅的杂志推送到你的邮箱了,而你收到的杂志都是你自己订阅的,不会不是你订阅的,这就是一个观察者模式的例子。订阅杂志的过程简单来说就是一个观察者(订阅者)向某个杂志社(发布者)订阅特定的杂志,其静态关系图如下所示:
从抽象的角度来看,上图所示的观察者模式是Obsevers向Subject订阅特定的消息(即杂志),因此一旦Subject对象需要通知观察者某些变化的时候,Subject对象将会发送update消息给每个观察者,而这些观察者值得是所有存储在Subject对象的内部列表中的订阅者。观察者模式是一种简单直接的设计模式,Subject为那些实现了Observer协议并且需要使用update消息的对象提供了注册和反注册的功能。当Subject对象发生了一些变化后,它会给自己发送消息通知,然后通过特定的广播算法向所有注册了的Observer发送update消息,其时序图如下所示:
使用观察者设计模式的最明显的好处就是能够为Subject对象扩展N个观察者,一个Subject可以对应无限个观察者(无限也要考虑系统资源的),只需要注册即可。
补个观察者的官方定义吧:
适用场景
在程序设计中,将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便,观察者就是解决这类的耦合关系的。当出现以下情况的时候,你可以考虑考虑观察者模式了:
- 当你有两个相互独立的抽象类的时候,通过把他们封装到一个独立的类之后,你依旧可以独立地变换以及重用他们。
- 当一个对象的变换需要引起其他变换的时候,尤其是需要一系列的对象需要跟着变换
- 当一个对象需要在不知道其他对象的具体情况而需要给他们发送通知的时候
CocoaTouch中的观察者模式
IOS开发过程中使用最多的MVC模式就包含了观察者设计模式,其中V(视图控制器)就是观察者,通过观察者设计模式,由于每个组件没有和其他组件存在多少的联系,因此他们可以自由地重用和扩展。
除了MVC设计模式,在Cocoa Touch的框架中,我们也能发现观察者设计模式的应用:Notifications和KVO(Key-Value Observer)
其中Notifications一般使用方法如下:
// 添加观察者 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeIntlCode:) name:NOTIFICATION_SUCCESS_SELECT_INTLCODE object:nil]; // 发出通知 [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SUCCESS_SELECT_INTLCODE object:nil userInfo:[NSDictionary dictionaryWithObject:model forKey:@"selectedIntlCodeModel"]]; // 移除观察者 [[NSNotificationCenter defaultCenter] removeObserver:self name:NOTIFICATION_SUCCESS_SELECT_INTLCODE object:nil];
KVO其实知识点比较多,这里也拿一些比较常见的代码来看看使用情况:
{ book = [[Book alloc] init]; // 通过setValue:forKey设置值 [book setValue:@"18.8" forKey:@"price"]; // 监视注册属性 [book addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL]; // .... } // NSKeyValueObserving定义的借口方法,重写实现回调方法 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if([keyPath isEqualToString:@"price"]) { // 通过valueForKy获取值 NSLog(@"%@", [book valueForKey:@"price"]); } } - (void)dealloc { [super dealloc]; [book removeObserver:self forKeyPath:@"price"]; [book release]; }
代码示例
(续)
总结
观察者模式可以使得订阅者及时获取被观察者的变换情况,支持多个观察者,同时也降低了Subject和具体的Observer的耦合性。