前言ide
与其说发布订阅是观察者模式的别名,还不如说发布订阅本质上是一种特殊的观察者模式;两种模式都主要是用于解除一个对象与多个对象之间的耦合,即无论有多少个监听者(observer),都不用改变被监听者(subject)的逻辑代码。测试
使用的场合atom
当你须要将某一个对象的改变通知全部的对象的,并且对象是什么类型也不肯定的的时候,就应该使用观察者模式,改变发生在同一个对象改变中,并在其余须要的地方更新内容。spa
因为上面我说过了,其实发布订阅与观察者模式仍是有区别的,下面咱们就经过一个例子,说明一下发布订阅与观察者模式的微小区别。code
观察者模式orm
我为了方便就没有去建立observer和subject的基类,而是直接建立了这两个的具体类(主要是方便测试,不想建立那么多文件),subject类中定义了- (void)addObserver:(NSObject *)obj selector:(SEL)aSelector;和- (void)notify;前者是添加观察者,后者是当subject的状态改变后,通知全部观察者的方法;server
(1)subject类;对象
#import <Foundation/Foundation.h> @interface Subject : NSObject - (void)addObserver:(NSObject *)obj selector:(SEL)aSelector; - (void)notify; @end #import "Subject.h" @interface Subject () @property (nonatomic, strong) NSMutableArray *observers; @end @implementation Subject - (void)addObserver:(NSObject *)obj selector:(SEL)aSelector { NSDictionary *dict = @{@"object":obj,@"sel":NSStringFromSelector(aSelector)}; [self.observers addObject:dict]; } - (void)notify { if (_observers) { for (NSDictionary *dict in _observers) { if ([dict isKindOfClass:[NSDictionary class]]) { NSObject *observer = dict[@"object"]; SEL aSelector = NSSelectorFromString(dict[@"sel"]); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [observer performSelector:aSelector]; #pragma clang diagnostic pop } } } } - (NSMutableArray *)observers { if (!_observers) { _observers = [NSMutableArray array]; } return _observers; } @end
(2)observer类,类中定义了name属性,以及一个update方法(响应subject的改变通知);get
#import <Foundation/Foundation.h> @interface Oberver : NSObject @property (nonatomic,strong) NSString *name; - (void)update; @end #import "Oberver.h" @implementation Oberver - (void)update { NSLog(@"我观察的目标发生了变化,我接收到了新的信息,%@",_name); } @end
发布订阅模式it
observer类我仍是沿用上面的类,新增NotifyCenter和Subscribe类;NotifyCenter中主要的方法有- (void)addObserver:(NSObject *)object selector:(SEL)aSelector name:(NSString *)aName;和- (void)notify:(NSString *)name;前者添加观察者对象,后者通知全部的观察者对象发生改变。说到这里确实看不出两种模式有什么区别;别急,再看Subscribe类,里面很简单,就一个- (void)change方法;
(1)NotifyCenter类;
#import <Foundation/Foundation.h> @class NotifyCenter; @interface NotifyCenter : NSObject + (NotifyCenter *)shared; - (void)addObserver:(NSObject *)object selector:(SEL)aSelector name:(NSString *)aName; - (void)notify:(NSString *)name; @end #import "NotifyCenter.h" @interface NotifyCenter () @property (nonatomic, strong) NSMutableSet *set; @property (nonatomic, strong) NSMutableArray *observers; @end @implementation NotifyCenter + (NotifyCenter *)shared { static NotifyCenter *shared; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ shared = [[self alloc] init]; }); return shared; } - (void)addObserver:(NSObject *)object selector:(SEL)aSelector name:(NSString *)aName { [self.set addObject:aName]; NSDictionary *dict = @{@"object":object,@"sel":NSStringFromSelector(aSelector)}; NSMutableDictionary *observer = [NSMutableDictionary dictionary]; observer[aName] = dict; [self.observers addObject:observer]; } - (void)notify:(NSString *)name { if ([_set containsObject:name]) { [_observers enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSDictionary *dict = obj[name]; if ([dict isKindOfClass:[NSDictionary class]]) { NSObject *observer = dict[@"object"]; SEL aSelector = NSSelectorFromString(dict[@"sel"]); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [observer performSelector:aSelector]; #pragma clang diagnostic pop } }]; } } - (NSMutableArray *)observers { if (!_observers) { _observers = [NSMutableArray array]; } return _observers; } - (NSMutableSet *)set { if (!_set) { _set = [NSMutableSet set]; } return _set; } @end
(2)Subscribe类;
#import <Foundation/Foundation.h> @interface Subscribe : NSObject - (void)change; @end #import "Subscribe.h" #import "NotifyCenter.h" @implementation Subscribe - (void)change { [[NotifyCenter shared] notify:@"change"]; } @end
下面咱们看看两个模式的使用,其实逻辑思路都是差很少的,发布订阅模式就比如将观察者模式的subject的逻辑,分为了发布订阅模式中的NotifyCenter和Subscribe,它每一个部分更加专一的完成各自的业务逻辑。
#import "ViewController.h" #import "Subject.h" #import "Oberver.h" #import "NotifyCenter.h" #import "Subscribe.h" @interface ViewController () @property (nonatomic, strong) Subject *subject; @property (nonatomic, strong) Subscribe *subscribe; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //观察者模式 self.subject = [[Subject alloc] init]; Oberver *one = [[Oberver alloc] init]; one.name = @"one"; [_subject addObserver:one selector:@selector(update)]; Oberver *two = [[Oberver alloc] init]; two.name = @"two"; [_subject addObserver:two selector:@selector(update)]; UIButton *testBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, 100, 40)]; testBtn.backgroundColor = [UIColor lightGrayColor]; [testBtn addTarget:self action:@selector(testButton) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:testBtn]; //发布订阅模式 self.subscribe = [[Subscribe alloc] init]; Oberver *third = [[Oberver alloc] init]; third.name = @"third"; [[NotifyCenter shared] addObserver:third selector:@selector(update) name:@"change"]; Oberver *four = [[Oberver alloc] init]; four.name = @"four"; [[NotifyCenter shared] addObserver:four selector:@selector(update) name:@"change"]; } - (void)testButton { NSLog(@"差很少11:45分了,到点吃饭了"); NSLog(@"观察者模式"); [_subject notify]; NSLog(@"发布-订阅模式"); [_subscribe change]; } @end
点击按钮,获得运行结果,结果很明了;
总结
关于这两种模式,其实大致上是相同的,而不一样的地方在于观察者模式调度的地方在subject类中,而发布订阅对订阅者的调度是在NotifyCenter调度中心;所以观察者模式subject和observer是存在依赖的,而发布订阅则不会,由于它是经过NotifyCenter对observer进行调度的。不过无论是观察者模式仍是发布订阅模式,都是为了一对多时的对象解耦,能够说发布订阅模式是一种特殊的观察者模式。