cocoa设计模式之观察者模式

     cocoa中我们常用的一种设计模式称为观察者模式(Observer)。它可以在对象之间建立一种一对多的依赖关系,当一个对象的状态发生改变的时候,所有依赖与它的对象都可以得到通知从而调用方法去更新。这一模式中关键对象是目标(或被观察者)和观察者(Observer)。一个目标可以有任意数目的依赖它的观察者。一旦目标的状态发生改变,所有的观察者都得到通知。每个观察者都将查询目标以使其状态与目标的状态同步。

比如说:用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。

观察者模式的适用性:

存在以下情况可以使用观察者模式。

1.当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使用它们各自独立地改变和复用。

2.当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象待改变。

3.当一个对象必须通知其它对象,而它又不能假定其它对象是谁,也就是说,你不希望这些对象是紧密耦合的。

观察者模式的参与者:

1)被观察的目标(Subject或Observed)

     目标知道它的观察者,可以有多个观察者观察同一个目标,由你注册所决定的。

      提供注册和删除观察者对象的接口。

2)观察者

为那些再目标发生改变时候需获得通知的对象定义一个更新的接口,比如调用某个方法去刷新。

下面举个简单的例子。

在cocoa中会用NSNotificationCenter这个类。在程序中这个类提供了一种广播通信的机制。

- (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector name:(NSString *)notificationName object:(id)notificationSender

这个方法就是给NSNotificationCenter的实例对象注册一个观察者。NSNotificationCenter采用了单例模式生成了一个唯一的实例对象,通过类方法+ (id)defaultCenter

可以获取这个唯一实例。

第一个参数id类型:不能为nil。这是目标对象注册的一个观察者。所以前面说过目标是知道它的观察者的。

第二个参数SEL : 指定方法名,要么不给参数,要给参数也只能给一个。

第三个参数NSString*类型: 消息名称

第四个参数:观者者想要接收消息的对象。

- (void)postNotificationName:(NSString*)notificationName object:(id)notificationSender userInfo:(NSDictionary *)userInfo

使用name创建消息,发送,携带信息,传递给接受者。

第一个参数:消息名称

第二个参数:传递消息的对象

第三个参数:消息携带的信息,可以是nil的。

- (void)removeObserver:(id)notificationObserver

移除注册。

参数:之前传的观察者对象。

kvo机制也是运用了观察者模式。

KVO:全称Key Value Observer,基于键值的观察者。

一个对象的某一个成员变量,它的变量名可以当作为key。通过kvc可以去设置那个变量的值,得到变量的值,不用通过自己定义的属性和方法而达到修改值的目的。

一个对象的某一个成员变量可以给它增加一个观察者对象。一旦这个被观察的对象的那个变量发生了改变,那么观察者就会接受到消息。

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context

这个是注册,给一个对象增加一个观察者对象。

第一个参数:观察者对象

第二个参数: 需要观察的键值,或者键路径

第三个参数:观察的选项。比如新值和旧值,NSKeyValueObservingOptionNew,观察新值,NSKeyValueObservingOptionOld,观察旧值。通常是两者都要。传入参数可以这样 NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld

第四个参数:一般给nil

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;

观察者对象接收消息的方法。一旦被观察对象的那个被观察的属性发生了改变,那么就会触发这个方法。新值和旧值都保存在change的字典里面。

- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

移除观察者对象,参数一就是之前注册的观察者对象。参数二就是被观察者的键路径

看看一个简单的程序实例吧:

Book类

#import <Foundation/Foundation.h>


@interface Book : NSObject

{

    NSString* name;

    float price;

}


@end


Book类的实现

#import "Book.h"


@implementation Book


@end

----------------------------------------------------

定一个myClass的类,继承NSObject。

myClass的声明。

#import <Foundation/Foundation.h>

@class Book;

@interface myClass : NSObject

{

    Book* book;

}


myClass的实现

#import "myClass.h"


@implementation myClass



-(id)init:(Book *)theBook

{

    if (self=[superinit]) {

        book=theBook;

        [bookaddObserver:selfforKeyPath:@"price" 

                  options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew

                  context:nil];  //监控新旧price

    }


    return self;

}


-(void)dealloc

{

   [bookremoveObserver:selfforKeyPath:@"price"];//移除去监控

    [super dealloc];

}



- (void)observeValueForKeyPath:(NSString *)keyPath 

                      ofObject:(id)object 

                        change:(NSDictionary *)change 

                       context:(void *)context{ 

    if([keyPath isEqual:@"price"]){ 

        NSLog(@">>>>>>>price is changed"); 

        NSLog(@"old price is %@",[changeobjectForKey:@"old"]); 

        NSLog(@"new price is %@",[changeobjectForKey:@"new"]); 

    } 

}

@end


代码分析:

给Book类的一个实例book,它有个成员变量。float price 。myClass注册成为Book类的观察者,通过myClass观察book类的price变化。一旦price发生了改变,那么myClass这个类就会触发下面这个方法,从而得到新值和旧值。

- (void)observeValueForKeyPath:(NSString *)keyPath 

                      ofObject:(id)object 

                        change:(NSDictionary *)change 

                       context:(void *)context;


观察者模式是一个很重要的设计模式。在cocoa中也常用到。也是类与类之间通信的一种常见的方式。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值