观察者模式,发布订阅模式(Publish-Subscribe Design Pattern)
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
在对象之间定义一个一对多依赖,当一对象状态改变的时候,所有依赖的对象都会自动收到通知。
观察者模式.jpg角色和职责
- Subject 主题,目标,被观察者
被观察的对象,当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。
Subject需要维持(添加、删除、通知)一个观察者对象的队列列表 - ConCreteSubject 具体目标
被观察者的具体实现,包含一些基本的属性状态及其他操作
将有关状态存入各ConCreteObserver
当它的状态发生改变时,向它的各个观察者发出通知 - Observer 观察者
接口或抽象类,当Subject的状态发生变化时,Observe对象将通过一个callback函数得到通知
为那些在目标发生改变时需获得通知的对象定义一个更新接口 - ConCreteObserve 具体观察者
存储有关状态,这些状态应与目标的状态保持一致
观察者的具体实现,得到通知后将完成一些具体的业务逻辑处理
代码示例
描述场景:定义了一种一对多的关系,让多个观对象(公司员工)同时监听一个主题对象(秘书),主题对象状态发生变化时,会通知所有的观察者,使它们能够更新自己。
#import <Foundation/Foundation.h>
@class Secretary;
//上班玩游戏的人,Observer观察者
@interface Player : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) Secretary *secretary;
@end
@implementation Player
- (instancetype)initWithName:(NSString *)name AndSecretary:(Secretary *)secretary {
if (self = [super init]) {
self.name = name;
self.secretary = secretary;
}
return self;
}
- (void)update:(NSString *)info {
NSLog(@"%@观察到了%@", self.name, info);
}
@end
//秘书 看见老板来了通知上班玩游戏的人 Subject被观察者
@interface Secretary : NSObject
@property (nonatomic, copy) NSString *action;
@property (nonatomic, strong) NSMutableArray *observers;
@end
@implementation Secretary
- (instancetype)init {
if (self = [super init]) {
self.observers = [NSMutableArray array];
}
return self;
}
- (void)addObserver:(Player *)player {
[self.observers addObject:player];
}
- (void)notify:(NSString *)info {
//给所有的观察者发送情报
for (Player *player in self.observers) {
[player update:info];
}
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Secretary *secretary = [[Secretary alloc] init];
Player *p1 = [[Player alloc] initWithName:@"张三" AndSecretary:secretary];
Player *p2 = [[Player alloc] initWithName:@"李四" AndSecretary:secretary];
[secretary addObserver:p1];
[secretary addObserver:p2];
[secretary notify:@"老板来了"];
[secretary notify:@"老板走了"];
}
return 0;
}
/*
张三观察到了老板来了
李四观察到了老板来了
张三观察到了老板走了
李四观察到了老板走了
*/
用处
- 侦听事件驱动程序设计中的外部事件
- 侦听/监视某个对象的状态变化
- 发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,通知邮件列表中的订阅者。
iOS中,KVO
和通知
就是观察者模式。
优点
- 观察者和被观察者是抽象耦合的。
被观察者仅知道它有一系列观察者,每个都符合抽象的Observer类的简单接口。被观察者不知道任何一个观察者属于哪一个具体的类。这样观察者和被观察者之间的耦合是抽象的和最小的。 - 支持广播通信
被观察者发送的通知不需要指定接收者,通知被自动广播给所有已向该被观察者对象登记的有关对象。处理还是忽略一个通知取决于观察者。
缺点
- 意外更新
因为一个观察者并不知道其它观察者的存在,它可能对改变被观察者的最终代价一无所知。
题外话
观察者模式和中介者模式都是为了实现参与者之间的解耦,简化交互。两者的不同在于应用场景上。在观察者模式的应用场景中,参与者之间的交互比较有条理,一般都是单向
的,一个参与者只有一个身份,要么是观察者,要么是被观察者。而在中介模式的应用场景中,参与者之间的交互关系错综复杂,既可以是消息的发送者也可以同时是消息的接收者。
除此之外,如果一个参与者状态改变,要求其他参与者执行操作有一定的先后顺序
,这时候,中介模式可以利用中介类,通过先后调用不同参与者的方法,来实现顺序操作,而观察者模式是无法实现这样的顺序要求的。
网友评论