摘自:http://www.cocoachina.com/applenews/devnews/2013/0506/6132.html

什么是观察者模式
什么是观察者模式?你曾经订阅过报纸吗?在订阅报纸的时候,你不用去任何地方,只需要将你的个人地址信息以及订阅信息告诉出版社,出版社就知道如何将相关报纸传递给你。这种模式的第二个名称叫做发布/订阅模式。

在GoF中是这样描述观察者模式的——观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式的的思想非常简单,Subject(主题)允许别的对象——观察者(这些对象实现了观察者接口)对这个Subject的改变进行订阅和取消订阅。当Subject发生了变化——那么Subject会将这个变化发送给所有的观察者,观察者就能对Subject的变化做出更新。在这里,Subject是报纸的出版社,而观察者则是订阅报纸的我和你,当Subject发生变化——有新的报纸,会做出通知——将报纸发送给所有的订阅者。

什么时候使用观察者模式?
当你需要将改变通知所有的对象时,而你又不知道这些对象的具体类型,此时就可以使用观察者模式。 改变发生在同一个对象中,并在别的地方需要将相关的状态进行更新。

iOS中观察者模式的实现方法
在iOS中观察者模式的实现有三种方法:Notification、KVO以及标准方法。

1.Notification
Notification - NotificationCenter机制使用了操作系统的功能。通过NSNotificationCenter可以让对象之间进行进行通讯,这些对象相互间可以不认识。当你用一个并行的流来推送通知,或者刷新数据库,并希望在界面中能够看到时,这非常有用。

NotificationCenter发布消息的方法如下所示:

1.NSNotification  * broadcastMessage = [ NSNotification  notificationWithName: AnyNotification  object: Self ];
2.NSNotificationCenter  * notificationCenter = [ NSNotificationCenter  defaultCenter];
3.[NotificationCenter postNotification: broadCastMessage];

上面的代码中,创建了一个NSNotification类型的对象,并指定名称为”broadcastMessage”,然后通过notificationCenter来发布这个消息。

要订阅感兴趣的对象中的相关事件,可以按照如下方法进行:

1.NSNotificationCenter  * notificationCenter = [ NSNotificationCenter  defaultCenter];
2.[NotificationCenter addObserver: Self  selector: @ selector (update:) name: AnyNotification  object: nil ];

如上代码所示:订阅了一个事件,并通过@selector指定了一个方法。

1.// 收到通知中心发来的通知
2.-(void)update:(NSNotification *) notification
3.{
4.    if ([[notification name] isEqualToString:AnyNotification])
5.        NSLog (@"成功收到通知中心发来的名为%@的通知", AnyNotification);
6.}

下面是运行上面代码,在控制台输出的内容:

1.2013-05-05 23:43:15.570 ObserverPattern[1738:c07] 成功收到通知中心发来的名为broadcastMessage的通知

2.KVO
通过KVO,某个对象中的特定属性发生了改变,别的对象可以获得通知。苹果官方文档对KVO有了很好的解释:Key-Value Observing Programming Guide。下面两种方法都可以改变对象中属性的值:

1.kvoSubj.changeableProperty = @"新的一个值";
2. 
3.[kvoSubj setValue:@"新的一个值" forKey:@"changeableProperty"];

上面这种值改变的灵活性可以让我们对键值进行观察。

下面是新建的一个类KVOSubject,这个类中有一个属性changeableProperty:

1.@interface KVOSubject : NSObject
2. 
3.@property (nonatomic, strong) NSString *changeableProperty;
4. 
5.@end
6. 
7.@implementation KVOSubject
8. 
9.@end

接着新建了另外一个类KVOObserver,通过该类可以监听changeableProperty属性值的改变。

1.@interface KVOObserver : NSObject
2.@end 
3.
4.@implementation KVOObserver 
5.
6.-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
7.{    
8.NSLog(@"KVO:值发生了改变");
9.} 
10.
11..@end

如上代码所示,KVOObserver类只有一个方法observeValueForKeyPath。当changeableProperty属性值的改变时,这个方法会被调用。下面是测试的代码:

1.- (IBAction)btnKVOObservationTest:(id)sender {    
2.KVOSubject *kvoSubj = [[KVOSubject alloc] init];    
3.KVOObserver *kvoObserver = [[KVOObserver alloc] init];
4.     
5.[kvoSubj addObserver:kvoObserver forKeyPath:@"changeableProperty"                 6.options:NSKeyValueObservingOptionNew context:nil];
7.     
8.kvoSubj.changeableProperty = @"新的一个值"; 
9.    
10.[kvoSubj setValue:@"新的一个值" forKey:@"changeableProperty"];
11.     
12.[kvoSubj removeObserver:kvoObserver forKeyPath:@"changeableProperty"];

13.}

执行上面的代码,可以看到控制台输出如下结果:

1.2013-05-05 23:10:20.789 ObserverPattern[1358:c07] KVO:值发生了改变
2.2013-05-05 23:10:20.790 ObserverPattern[1358:c07] KVO:值发生了改变标准方法

3.标准方法

先来看看Gof中对观察者模式定义的结构图:


 

标准方法的实现是这样的:Subject(主题)知道所有的观察者,但是不知道它们的类型。下面我们就从创建Subject和Observer(观察者)的协议(protocol)开始。

1.@protocol StandardObserver 
2.-(void) valueChanged:(NSString *)valueName newValue:(NSString *) newValue;
3.@end
4. 
5.@protocol StandardSubject 
6.-(void) addObserver:(id) observer;
7.-(void) removeObserver:(id) observer;
8.-(void) notifyObjects;
9.@end

下面,我们来创建一个Subject的implementation (实现)
1.@interface StandardSubjectImplementation : NSObject 
2.{
3.    @private NSString *_valueName;
4.    @private NSString *_newValue;
5.}
6.@property (nonatomic, strong) NSMutableSet *observerCollection;
7.-(void)changeValue:(NSString *)valueName andValue:(NSString *) newValue;
8.@end
9. 
10.@implementation StandardSubjectImplementation
11. 
12.-(NSMutableSet *) observerCollection
13.{
14.    if (_observerCollection == nil)
15.        _observerCollection = [[NSMutableSet alloc] init];
16. 
17.    return _observerCollection;
18.}
19. 
20.-(void) addObserver:(id)observer
21.{
22.    [self.observerCollection addObject:observer];
23.}
24. 
25.-(void) removeObserver:(id)observer
26.{
27.    [self.observerCollection removeObject:observer];
28.}
29. 
30.-(void) notifyObjects
31.{
32.    for (id observer in self.observerCollection) {
33.        [observer valueChanged: _valueName newValue:_newValue];
34.    }
35.}
36. 
37.-(void)changeValue:(NSString *)valueName andValue:(NSString *) newValue
38.{
39.    _newValue = newValue;
40.    _valueName = valueName;
41.    [self notifyObjects];
42.}
43.@end

接下来是Observer的implementation (实现):

1.@interface SomeSubscriber : NSObject 
2.@end
3. 
4.@implementation SomeSubscriber
5.-(void) valueChanged:(NSString *)valueName newValue:(NSString *)newValue
6.{
7.    NSLog(@"SomeSubscriber输出: 值 %@ 已变为 %@", valueName, newValue);
8.}
9.@end
10. 
11.@interface OtherSubscriber : NSObject 
12. 
13.@end
14. 
15.@implementation OtherSubscriber
16. 
17.-(void) valueChanged:(NSString *)valueName newValue:(NSString *)newValue
18.{
19.    NSLog(@"OtherSubscriber输出: 值 %@ 已变为 %@", valueName, newValue);
20.}
21.@end

下面是演示的代码:
1.StandardSubjectImplementation * subj = [[StandardSubjectImplementation alloc] init];
2.SomeSubscriber * someSubscriber = [[SomeSubscriber alloc] init];
3.OtherSubscriber * otherSubscriber = [[OtherSubscriber alloc] init];
4. 
5.[Subj addObserver: someSubscriber];
6.[Subj addObserver: otherSubscriber];
7. 
8.[subj changeValue:@"version" andValue:@"1.0.0"];

上面代码运行的log如下所示:
1.2013-05-05 23:19:04.662 ObserverPattern[1459:c07] OtherSubscriber输出: 值 version 已变为 1.0.0
2.2013-05-05 23:19:04.664 ObserverPattern[1459:c07] SomeSubscriber输出: 值 version 已变为 1.0.0

本示例的代码可以在这里下载到:https://github.com/BeyondVincent/ios_patterns/tree/master/ObserverPattern

参考:http://maleevdimka.wordpress.com/2013/02/16/ios-patterns-observer/

PDF下载:

/cms/uploads/soft/130506/4196-130506101124.pdf

iOS设计模式:观察者的更多相关文章

  1. iOS设计模式(01):观察者

    iOS设计模式(01):观察者 iOS-Observer-Pattern 什么是观察者模式 什么是观察者模式?你曾经订阅过报纸吗?在订阅报纸的时候,你不用去任何地方,只需要将你的个人地址信息以及订阅信 ...

  2. IOS设计模式之一(MVC模式,单例模式)

    iOS 设计模式-你可能已经听说过这个词,但是你真正理解它意味着什么吗?虽然大多数的开发者可能都会认为设计模式是非常重要的,然而关于设计模式这一主题的文章却不多,并且有时候我们开发者在写代码的时候也不 ...

  3. iOS 设计模式

    很赞的总结 iOS Design Patterns 中文版 IOS设计模式之一(MVC模式,单例模式) IOS设计模式之二(门面模式,装饰器模式) IOS设计模式之三(适配器模式,观察者模式) IOS ...

  4. iOS 设计模式之工厂模式

    iOS 设计模式之工厂模式 分类: 设计模式2014-02-10 18:05 11020人阅读 评论(2) 收藏 举报 ios设计模式 工厂模式我的理解是:他就是为了创建对象的 创建对象的时候,我们一 ...

  5. iOS设计模式之生成器

    iOS设计模式之生成器 1.生成器模式的定义 (1): 将一个复杂的对象的构件与它的表示分离,使得相同的构建过程能够创建不同的表示 (2): 生成器模式除了客户之外还包括一个Director(指导者) ...

  6. IOS设计模式之三:MVC模式

    IOS设计模式之三:MVC模式   模型-视图-控制器 这个模式其实应该叫做MCV,用控制器把model与view隔开才对,也就是model与view互相不知道对方的存在,没有任何瓜葛,他们就像一个团 ...

  7. iOS设计模式 - 享元

    iOS设计模式 - 享元 原理图 说明 享元模式使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件:它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件.通常物件中的部分 ...

  8. iOS设计模式 - 责任链

    iOS设计模式 - 责任链 原理图 说明 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链 ...

  9. iOS设计模式 - 模板

    iOS设计模式 - 模板 原理图 说明 定义一个操作中的算法的骨架,而将步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤. 源码 https://github.c ...

随机推荐

  1. Django的TemplateResponse

    def my_render_callback(response): return response from django.template.response import TemplateRespo ...

  2. Objective-c 程序结构

    类是Objective-c的核心,Objective-c程序都是围绕类进行的.Objective-c程序至少包含以下三个部分: 1.类接口:定义了类的数据和方法,但是不包括方法的实现代码. 2.类实现 ...

  3. Ext JS学习第十天 Ext基础之动态加载JS文件(补充)

    此文用来记录学习笔记: •Ext4.x版本提供的一大亮点就是Ext.Loader这个类的动态加载机制!只要遵循路径规范,即可动态加载js文件,方便把自己扩展组件动态加载进来,并且减轻浏览器的压力. • ...

  4. javaweb学习路之一--web项目搭建

    概述: 工作闲暇时间想要自己搭建一个web项目玩玩,没想到大半天才弄了一个springMVC+mybatis的网站,简直菜的不行,以下记录所有的步骤加深印象 使用环境 1.jdk1.8 2.maven ...

  5. DevExpress ASP.NET 使用经验谈(3)-XPO对象的使用(使用指定数据连接)

    首先,我们贴出上一节Users类XPO对象的保存代码,直接建立的XPO Session会话,因为没有与我们所期望的数据层建立绑定, 所以程序自动创建了一个Access数据库,作为默认数据库操作对象来使 ...

  6. 转换GridView的内容到Excel里面 ---带有格式

    http://www.aspsnippets.com/Articles/Export-GridView-to-Excel-in-ASPNet-with-Formatting-using-C-and-V ...

  7. excel条型图示例

    不怎么用这个功能,今天同事问我,研究了半天,有的地方还是有糊涂的地方,网上,书上都介绍的比较少.比如一张表里没有数据内容时,形成表时会有问题.但形成表后,再删除单元格数据,表却没有问题. 有点矛盾.

  8. 【转】Nginx+Tomcat搭建高性能负载均衡集群

    最近对负载均衡比较感兴趣,研究了公司的负载均衡的配置,用的是阿里的SLB,相当于不用运维,只需要在后台进行简单的配置就能完成Tomcat的负载均衡,索性在网上找了几篇文章去尝试搭建一个集群,然而很多都 ...

  9. drawInRect:withAttributes:

    - (void)drawRect:(CGRect)frame { NSMutableParagraphStyle *textStyle = [[NSMutableParagraphStyle defa ...

  10. JS使用合并数组

    var arr= [4,5,6]; var arr1 = [7,8,9]; var arr2=[1,2,3]; arr.concat(arr1,arr2); //或者使用Arry.prototype. ...