• 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];
                  }
              }
          }
    • 结构图


    三,代码示例

    • 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

      观察者模式

  • 相关阅读:
    Superset 制作图表
    superset 安装配置
    python 虚拟环境 pyenv
    pymysql 单独获取表的栏位名称
    pymysql 返回数据为字典形式(key:value--列:值)
    Oracle/MySQL decimal/int/number 转字符串
    netstat 问题处理
    MySQL 中Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化
    MySQL执行计划extra中的using index 和 using where using index 的区别
    ref与out
  • 原文地址:https://www.cnblogs.com/lxlx1798/p/11483844.html
Copyright © 2020-2023  润新知