观察者模式:定义了对象之间一对多的依赖,那么在一个对象状态改变时,它所有依赖的对象都会收到通知并自动更新。
观察者模式是众多的行为性模式之一。观察者模式定义上来看就很简单。在iOS中NSNOtifycationCenter,KVO,就是用观察者模式来实现的。当然这里我们不会直接拿iOS的API,而是分析下它的内部逻辑,方便理解。所以如果是真心想理解观察者模式的iOS开发者,还是可以好好看看它的内部实现。
观察者模式这个类图是从HeadFirst中截取的,上面的描述很清晰。观察者由主题Subject)和观察者(Observer)组成。主题在改变时通知观察者做出更新。
举个栗子
农场主种了一棵很特别的苹果树,等待着结果。
等待结果的不仅仅是农场主,当地的商贩也看中了这棵果树,也等着它开花结果。
那这里有一个主题(subject)果树
有两个观察者分别是农场主和商贩。农场主和商贩不可能每天都去看啥时候成熟,所以不如让果树能自动更新它的数据给农场主和商贩。
观察者协议
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol ObserverObject <NSObject>
-(void)update:(NSDictionary *)userInfo;
@end
NS_ASSUME_NONNULL_END
被观察者协议(subject)
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol ObServerProtocol <NSObject>
@property(nonatomic, strong) NSMutableArray * observers;
-(void)registerObserver:(id)observer;
-(void)removeObserver:(id)observer;
-(void)notifyObserver;
@end
NS_ASSUME_NONNULL_END
苹果树的实现(ConcreteSubject)
#import "AppleTree.h"
#import "ObserverObject.h"
@interface AppleTree ()
@property(nonatomic, assign)float height;
@property(nonatomic, assign)BOOL isOpen;
@property(nonatomic, assign)BOOL isRipen;
@end
@implementation AppleTree
@synthesize observers = _observers;
-(instancetype)init {
if (self = [super init]) {
_observers = [NSMutableArray array];
[self grewUp];
}return self;
}
- (void)notifyObserver {
//循环遍历观察者对象,并对观察者对象发出通知
[_observers enumerateObjectsUsingBlock:^(id<ObserverObject> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSMutableDictionary * temp = [NSMutableDictionary dictionary];
temp[@"height"] = @(_height);
temp[@"isOpen"] = @(_isOpen);
temp[@"isRipen"] = @(_isRipen);
[obj update:temp];
}];
}
- (void)registerObserver:(nonnull id)observer {
if (![_observers containsObject:observer]) {
[_observers addObject:observer];
}
}
- (void)removeObserver:(nonnull id)observer {
if ([_observers containsObject:observer]) {
[_observers removeObject:observer];
}
}
//模拟一段生长过程
-(void)grewUp {
[NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
_height += 0.2;
if (_height >= 1.2 && _height < 1.5) _isOpen = true;
else _isOpen = false;
if (_height > 2.0) {
_isRipen = YES;
}
[self notifyObserver];
}];
}
@end
农场主实现(ConcreteObserver)
#import "Farmer.h"
@implementation Farmer
-(instancetype)initWithAppleTree:(AppleTree *)appleTree {
if (self = [super init]) {
_appleTree = appleTree;
[_appleTree registerObserver:self];
}return self;
}
-(void)update:(NSDictionary *)userInfo {
float height = [userInfo[@"height"] floatValue];
BOOL isOpen = [userInfo[@"isOpen"] boolValue];
NSLog(@"当前树高%f",height);
if (isOpen) {
NSLog(@"已经开花了,开始施肥");
}
}
@end
商贩的实现 (ConcreteObserver)
#import "Trader.h"
@implementation Trader
-(instancetype)initWithAppleTree:(AppleTree *)appleTree {
if (self = [super init]) {
_appleTree = appleTree;
[_appleTree registerObserver:self];
}return self;
}
-(void)update:(NSDictionary *)userInfo {
BOOL isRipen = [userInfo[@"isRipen"] boolValue];
if (isRipen) {
NSLog(@"苹果成熟了,可以收购了");
}
}
@end
具体调用
tree = [[AppleTree alloc] init];
farmer = [[Farmer alloc] initWithAppleTree:tree];
trader = [[Trader alloc] initWithAppleTree:tree];
优点
1.观察者模式是基于抽象耦合的。
2.观察者模式建立起了一套触发机制,可以在对象改变的时候让观察者响应。
缺点
1.如果一个对象有太多的直接或者间接的观察者,那么将所有的观察者都通知到会很耗时间
2.观察者并不知道主题对象是如何变化的(也可以作为它的优点)
网友评论