iOS设计模式之观察者模式

一,什么是观察者模式

  • 定义:
    定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
  • 需求场景:
    当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变;或者一个对象必须通知其它对象,而它又不能假定其它对象是谁,换言之,我们不希望这些对象是紧密耦合的。这时我们就可以利用到观察者模式。
  • 示例
    在IOS中典型的推模型实现方式为NSNotificationCenter和KVO。

二,观察者模式的结构图

  • 实现步骤:
    1. 定义观察者中心类,用于订阅号的注册,及管理消息的发送,观察者对象的释放。
    2. 定义接口协议,用于观察者的代理回调
    3. 实现添加订阅号,添加订阅号观察者,订阅号消息发送,移除订阅号及观察者对象
  • 注意点
    1.对象容器的结构:{key:(NSHashTable),key:(NSHashTable)...}
    2.订阅号下消息代理回调:
      NSHashTable *hashTable = [self existSubscriptionNumber:subscriptionNumber];
        if (hashTable) {
            NSEnumerator *enumerator = [hashTable objectEnumerator];
            id <SubscriptionServiceCenterProtocol> customer = nil;
            while (customer = [enumerator nextObject]) {
            
                if ([customer respondsToSelector:@selector(subscriptionMessage:subscriptionNumber:)]) {
                    [customer subscriptionMessage:message subscriptionNumber:subscriptionNumber];
                }
            }
        }
  • 结构图
    iOS设计模式之观察者模式


三,代码示例

  • SubscriptionServiceCenter
    • SubscriptionServiceCenter.h
      #import <Foundation/Foundation.h>
      #import "SubscriptionServiceCenterProtocol.h"
      
      /**
       *  订阅服务中心(实现了系统的通知中心业务逻辑)
       *
       *  = 注意 = 没有考虑发送通知的时候,同步与异步的问题
       *
       */
      @interface SubscriptionServiceCenter : NSObject
      
      /**
       *  创建订阅号
       *
       *  @param subscriptionNumber 订阅号码
       */
      + (void)createSubscriptionNumber:(NSString *)subscriptionNumber;
      
      /**
       *  移除订阅号(参与到该订阅号码的所有客户不会再收到订阅信息)
       *
       *  @param subscriptionNumber 订阅号码
       */
      + (void)removeSubscriptionNumber:(NSString *)subscriptionNumber;
      
      /**
       *  客户订阅指定的订阅号
       *
       *  @param customer           客户对象
       *  @param subscriptionNumber 订阅号码
       */
      + (void)addCustomer:(id <SubscriptionServiceCenterProtocol>)customer withSubscriptionNumber:(NSString *)subscriptionNumber;
      
      /**
       *  将指定客户从指定订阅号上移除掉
       *
       *  @param customer           客户对象
       *  @param subscriptionNumber 订阅号码
       */
      + (void)removeCustomer:(id <SubscriptionServiceCenterProtocol>)customer fromSubscriptionNumber:(NSString *)subscriptionNumber;
      
      /**
       *  通知签订了订阅号码的对象
       *
       *  @param message            信息对象
       *  @param subscriptionNumber 订阅号码
       */
      + (void)sendMessage:(id)message toSubscriptionNumber:(NSString *)subscriptionNumber;
      
      @end
    • SubscriptionServiceCenter.m
      #import "SubscriptionServiceCenter.h"
      
      static  NSMutableDictionary  *_subscriptionNumberDictionary = nil;
      
      @implementation SubscriptionServiceCenter
      
      #pragma mark - 初始化
      + (void)initialize {
          
          if (self == [SubscriptionServiceCenter class]) {
              _subscriptionNumberDictionary = [NSMutableDictionary dictionary];
          }
      }
      
      + (void)createSubscriptionNumber:(NSString *)subscriptionNumber {
      
          NSParameterAssert(subscriptionNumber);
          
          NSHashTable *hashTable = [self existSubscriptionNumber:subscriptionNumber];
          
          if (hashTable == nil) {
              hashTable = [NSHashTable weakObjectsHashTable];
              [_subscriptionNumberDictionary setObject:hashTable forKey:subscriptionNumber];
          }
      }
      
      + (void)removeSubscriptionNumber:(NSString *)subscriptionNumber {
      
          NSParameterAssert(subscriptionNumber);
          
          if ([self existSubscriptionNumber:subscriptionNumber]) {
              [_subscriptionNumberDictionary removeObjectForKey:subscriptionNumber];
          }
      }
      
      + (void)removeCustomer:(id <SubscriptionServiceCenterProtocol>)customer fromSubscriptionNumber:(NSString *)subscriptionNumber {
          NSParameterAssert(subscriptionNumber);
          
          NSHashTable *hashTable = [self existSubscriptionNumber:subscriptionNumber];
          
          if (hashTable && customer) {
              [hashTable removeObject:customer];
          }
      }
      
      + (void)sendMessage:(id)message toSubscriptionNumber:(NSString *)subscriptionNumber {
          
          NSParameterAssert(subscriptionNumber);
          
          NSHashTable *hashTable = [self existSubscriptionNumber:subscriptionNumber];
          
          if (hashTable) {
              NSEnumerator *enumerator = [hashTable objectEnumerator];
              
              id <SubscriptionServiceCenterProtocol> customer = nil;
              while (customer = [enumerator nextObject]) {
              
                  if ([customer respondsToSelector:@selector(subscriptionMessage:subscriptionNumber:)]) {
                      [customer subscriptionMessage:message subscriptionNumber:subscriptionNumber];
                  }
              }
          }
      }
      
      + (void)addCustomer:(id)customer withSubscriptionNumber:(NSString *)subscriptionNumber {
      
          NSParameterAssert(customer);
          NSParameterAssert(subscriptionNumber);
          
          NSHashTable *hashTable = [self existSubscriptionNumber:subscriptionNumber];
          [hashTable addObject:customer];
      }
      
      #pragma mark - 私有方法
      + (NSHashTable *)existSubscriptionNumber:(NSString *)subscriptionNumber {
          return [_subscriptionNumberDictionary objectForKey:subscriptionNumber];
      }
      
      @end
    • SubscriptionServiceCenterProtocol.h
      #import <Foundation/Foundation.h>
      @protocol SubscriptionServiceCenterProtocol <NSObject>
      
      /**
       *  接收到的订阅信息
       *
       *  @param message            订阅信息
       *  @param subscriptionNumber 订阅编号
       */
      - (void)subscriptionMessage:(id)message subscriptionNumber:(NSString *)subscriptionNumber;
      
      @end
  • ViewController
    #import "ViewController.h"
    #import "SubscriptionServiceCenter.h"
    
    #define  SCIENCE  @"SCIENCE"
    #define  NEWTON   @"NEWTON"
    
    @interface ViewController ()<SubscriptionServiceCenterProtocol>
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        
        [super viewDidLoad];
        
        // 创建订阅号 - SCIENCE NEWTON
        [SubscriptionServiceCenter createSubscriptionNumber:SCIENCE];
        [SubscriptionServiceCenter createSubscriptionNumber:NEWTON];
        
        // 客户添加了订阅号 - SCIENCE NEWTON
        [SubscriptionServiceCenter addCustomer:self withSubscriptionNumber:SCIENCE];
        [SubscriptionServiceCenter addCustomer:self withSubscriptionNumber:NEWTON];
        
        // 订阅中心给订阅号 - SCIENCE NEWTON 发送订阅信息
        [SubscriptionServiceCenter sendMessage:@"爱因斯坦" toSubscriptionNumber:SCIENCE];
        [SubscriptionServiceCenter sendMessage:@"小苹果" toSubscriptionNumber:NEWTON];
    }
    
    - (void)subscriptionMessage:(id)message subscriptionNumber:(NSString *)subscriptionNumber {
        
        if ([subscriptionNumber isEqualToString:NEWTON]) {
            
            NSLog(@"来自于牛顿杂志的信息 - %@", message);
            
        } else if ([subscriptionNumber isEqualToString:SCIENCE]) {
            
            NSLog(@"来自于科学美国人杂志的信息 - %@", message);
        }
    }
    @end
  • 打印结果:
    2019-09-07 23:21:44.685105+0800 SystemNotificationCenter[24007:6871723] 来自于科学美国人杂志的信息 - 爱因斯坦
    2019-09-07 23:21:44.685360+0800 SystemNotificationCenter[24007:6871723] 来自于牛顿杂志的信息 - 小苹果

 

四,demo

  观察者模式

iOS设计模式之观察者模式

上一篇:C#调用C/C++动态库 封送结构体,结构体数组


下一篇:mv:移动文件或改名