标签:设计模式 observer observer pattern 观察者模式 观察者设计模式
观察者设计模式也叫做发布-订阅(Publish-Subscribe)模式。有点像杂志订阅的意思,你向杂志社订阅杂志,然后提供了自己的姓名和邮箱地址,这样杂志社就可以把你所订阅的杂志推送到你的邮箱了,而你收到的杂志都是你自己订阅的,不会不是你订阅的,这就是一个观察者模式的例子。订阅杂志的过程简单来说就是一个观察者(订阅者)向某个杂志社(发布者)订阅特定的杂志,其静态关系图如下所示:
从抽象的角度来看,上图所示的观察者模式是Obsevers向Subject订阅特定的消息(即杂志),因此一旦Subject对象需要通知观察者某些变化的时候,Subject对象将会发送update消息给每个观察者,而这些观察者值得是所有存储在Subject对象的内部列表中的订阅者。观察者模式是一种简单直接的设计模式,Subject为那些实现了Observer协议并且需要使用update消息的对象提供了注册和反注册的功能。当Subject对象发生了一些变化后,它会给自己发送消息通知,然后通过特定的广播算法向所有注册了的Observer发送update消息,其时序图如下所示:
使用观察者设计模式的最明显的好处就是能够为Subject对象扩展N个观察者,一个Subject可以对应无限个观察者(无限也要考虑系统资源的),只需要注册即可。
补个观察者的官方定义吧:
在程序设计中,将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便,观察者就是解决这类的耦合关系的。当出现以下情况的时候,你可以考虑考虑观察者模式了:
// 添加观察者 [[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]; }
// // Publisher.h // ObserverDemo // // Created by God Lin on 15/1/22. // Copyright (c) 2015年 arbboter. All rights reserved. // #import <Foundation/Foundation.h> @class Observer; // 定义抽象主题协议 @protocol Subject <NSObject> @required // 注册观察者 - (void) doRegister:(Observer*) observer; // 反注册观察者 - (void) unRegister:(Observer*) observer; // 为观察者发送通知 - (void) notifyObservers; @end // 出版社 @interface Publisher : NSObject <Subject> @property (nonatomic, strong) NSMutableArray* observerArray; // 新出版了杂志 - (void) pulishNew; @end
// // Publisher.m // ObserverDemo // // Created by God Lin on 15/1/22. // Copyright (c) 2015年 arbboter. All rights reserved. // #import "Publisher.h" #import "Observer.h" @implementation Publisher - (id) init { if(self = [super init]) { _observerArray = [[NSMutableArray alloc] init]; } return self; } #pragma mark -- 实现协议Subject // 注册观察者 - (void) doRegister:(Observer*) observer { [self.observerArray addObject:observer]; } // 反注册观察者 - (void) unRegister:(Observer*) observer { if([self.observerArray indexOfObject:observer] != NSNotFound) { [self.observerArray removeObject:observer]; } } // 为观察者发送通知 - (void) notifyObservers { NSLog(@"我杂志社新发布了杂志了!!!"); // 通知每个注册了得观察者 for (Observer* o in self.observerArray) { [o foundNew]; } } - (void) pulishNew { // 发布通知 [self notifyObservers]; } @end抽象出来的观察者Observer实现定义如下,该抽象是Subject所知道的,Subject熟知该抽象接口:
#import <Foundation/Foundation.h> @interface Observer : NSObject // 通知观察者有新发现 - (void) foundNew; @end
#import "Observer.h" @implementation Observer // 通知观察者有新发现 - (void) foundNew { NSLog(@"I Know."); } @end读者是继承抽象的Observer,实现重写接口的,具体实现如下:
#import "Observer.h" @interface Reader : Observer @property (nonatomic, strong) NSString* name; - (id) initWithName:(NSString*)myName; @end
#import "Reader.h" @implementation Reader - (id) initWithName:(NSString*)myName { if(self = [super init]) { self.name = myName; } return self; } - (void) foundNew { NSLog(@"[%@]哇哈哈,又有好东西可以看了!!!", self.name); } @end
// // main.m // ObserverDemo // // Created by God Lin on 15/1/22. // Copyright (c) 2015年 arbboter. All rights reserved. // #import <Foundation/Foundation.h> #import "Publisher.h" #import "Reader.h" int main(int argc, const char * argv[]) { Publisher* publisher = [[Publisher alloc] init]; NSString* name = nil; Reader* reader = nil; // 保存为了反注册 NSMutableArray* readers = [[NSMutableArray alloc] init]; for (NSInteger i=0; i<5; i++) { name = [NSString stringWithFormat:@"reader %ld", i+1]; reader = [[Reader alloc] initWithName:name]; // 注册 [publisher doRegister:reader]; // 为了反注册 [readers addObject:reader]; } // 杂志社出新杂志了 [publisher pulishNew]; // 反注册 for (Reader* r in readers) { [publisher unRegister:r]; } return 0; }输出结果为:
2015-01-22 23:47:38.637 ObserverDemo[19997:38042854] 我杂志社新发布了杂志了!!! 2015-01-22 23:47:38.638 ObserverDemo[19997:38042854] [reader 1]哇哈哈,又有好东西可以看了!!! 2015-01-22 23:47:38.639 ObserverDemo[19997:38042854] [reader 2]哇哈哈,又有好东西可以看了!!! 2015-01-22 23:47:38.639 ObserverDemo[19997:38042854] [reader 3]哇哈哈,又有好东西可以看了!!! 2015-01-22 23:47:38.639 ObserverDemo[19997:38042854] [reader 4]哇哈哈,又有好东西可以看了!!! 2015-01-22 23:47:38.639 ObserverDemo[19997:38042854] [reader 5]哇哈哈,又有好东西可以看了!!! Program ended with exit code: 0可以从上述代码中看到,Subject需要依赖于观察者的抽象接口(一个缺点),需要在通知的时候使用者写接口。读者通过向杂志社发送注册消息后,当杂志社新出版了杂志后,每个杂志的订阅者可以立刻获取最新的杂志。
标签:设计模式 observer observer pattern 观察者模式 观察者设计模式
原文地址:http://blog.csdn.net/arbboter/article/details/43051133