iOS设计模式

  • 五种设计模式:责任链模式、桥接模式、适配器模式、单例模式、命令模式。
  • 六大设计原则:单一职责、开闭原则、 接口隔离原则、依赖倒置原则、里式替换原则、迪米特法责。

六大设计原则

  • 单一职责:一个类只负责一件事,如:UIview负责事件传递及事件响应、calayer负责动画及视图显示。
  • 开闭原则:对修改关闭,对扩展开放。
  • 接口隔离原则:使用多个专门的协议,而不是一个庞大臃* 肿的协议,如tableview的delegate和DataSource
  • 依赖倒置原则:抽象不应该依赖具体实现,具体实现可以依赖于抽象,如上层多个调用可使用同一个接口,接口内部可以有不同的实现方案
  • 里式替换原则:父类可以被子类无缝替换,且原有功能不受影响,如KVO
  • 迪米特法责:一个对象应当对其他对象有尽可能少的了解,高内聚、低耦合

设计模式:

  • 责任链:如:业务A->业务B->业务C 当需求变更为 业务C->业务B->业务A 可以使用责任链模式解决

       #import <Foundation/Foundation.h>
      @class BusinessObject;
      typedef void(^CompletionBlock)(BOOL handled);
      typedef void(^ResultBlock)(BusinessObject *handler, BOOL handled);
    
      @interface BusinessObject : NSObject
      // 下一个响应者(响应链构成的关键)
      @property (nonatomic, strong) BusinessObject *nextBusiness;
      // 响应者的处理方法
      - (void)handle:(ResultBlock)result;
      // 各个业务在该方法当中做实际业务处理
      - (void)handleBusiness:(CompletionBlock)completion;
      @end
    
    
      #import "BusinessObject.h"
      @implementation BusinessObject
    
      // 责任链入口方法
      - (void)handle:(ResultBlock)result
      {
          CompletionBlock completion = ^(BOOL handled){
              // 当前业务处理掉了,上抛结果
              if (handled) {
                  result(self, handled);
              }
              else{
                  // 沿着责任链,指派给下一个业务处理
                  if (self.nextBusiness) {
                      [self.nextBusiness handle:result];
                  }
                  else{
                      // 没有业务处理, 上抛
                      result(nil, NO);
                  }
              }
          };
          
          // 当前业务进行处理
          [self handleBusiness:completion];
      }
    
      - (void)handleBusiness:(CompletionBlock)completion
      {
          /*
           业务逻辑处理
           如网络请求、本地照片查询等
            处理完成后回调CompletionBlock
           */
      }
      @end
    
  • 桥接:

依赖倒置


image.png

image.png
  代码示例
    #import <Foundation/Foundation.h>
    @interface BridgeDemo : NSObject
    - (void)fetch;
    @end

    #import "BridgeDemo.h"
    #import "BaseObjectA.h"
    #import "BaseObjectB.h"
    #import "ObjectA1.h"
    #import "ObjectA2.h"
    #import "ObjectB1.h"
    #import "ObjectB2.h"
    @interface BridgeDemo()
    @property (nonatomic, strong) BaseObjectA *objA;
    @end

    @implementation BridgeDemo

    /*
     根据实际业务判断使用那套具体数据
     A1 --> B1、B2、B3         3种
     A2 --> B1、B2、B3         3种
     A3 --> B1、B2、B3         3种
     */
    - (void)fetch
    {
        // 创建一个具体的ClassA
        _objA = [[ObjectA1 alloc] init];
        
        // 创建一个具体的ClassB
        BaseObjectB *b1 = [[ObjectB1 alloc] init];
        // 将一个具体的ClassB1 指定给抽象的ClassB
        _objA.objB = b1;
        
        // 获取数据
        [_objA handle];
    }
    @end

    #import <Foundation/Foundation.h>
    #import "BaseObjectB.h"
    @interface BaseObjectA : NSObject
    // 桥接模式的核心实现
    @property (nonatomic, strong) BaseObjectB *objB;
    // 获取数据
    - (void)handle;
    @end

    #import "BaseObjectA.h"
    @implementation BaseObjectA
     /*
        A1 --> B1、B2、B3         3种
        A2 --> B1、B2、B3         3种
        A3 --> B1、B2、B3         3种
      */
    - (void)handle
    {
        // override to subclass
        [self.objB fetchData];
    }
    @end

    #import "ObjectA1.h"
    @implementation ObjectA1
    - (void)handle
    {
        // before 业务逻辑操作
        [super handle];
        // after 业务逻辑操作
    }
    @end

    #import "ObjectA2.h"
    @implementation ObjectA2
    - (void)handle
    {
        // before 业务逻辑操作
        [super handle];
        // after 业务逻辑操作
    }
    @end

    #import <Foundation/Foundation.h>
    @interface BaseObjectB : NSObject
    - (void)fetchData;
    @end

    #import "BaseObjectB.h"
    @implementation BaseObjectB
    - (void)fetchData
    {
        // override to subclass
        //抽象类,具体实现放到子类中
    }
    @end

    #import "ObjectB1.h"
    @implementation ObjectB1
    - (void)fetchData{
        // 具体的逻辑处理
    }
    @end

    #import "ObjectB2.h"
    @implementation ObjectB2
    - (void)fetchData{
        // 具体的逻辑处理
    }
    @end
  • 适配器:
    一个现有类需要适应变化的问题
    对象适配器
    类适配器
image.png

-(void)request{//新类中的方法
//适配逻辑,添加额外的方法
[被适配对象 某方法];//可能是多个方法
//适配逻辑,添加额外的方法
}

  • 单例:

    + (id)sharedInstance
      {
          // 静态局部变量
          static ClassA *instance = nil;
          
          // 通过dispatch_once方式 确保instance在多线程环境下只被创建一次
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
              // 创建实例
              //要使用super(使用self会引起循环调用)
              instance = [[super allocWithZone:NULL] init];
          });
          return instance;
      }
    
      // 重写方法【必不可少】
      + (id)allocWithZone:(struct _NSZone *)zone{
          return [self sharedInstance];
      }
    
      // 重写方法【必不可少】
      - (id)copyWithZone:(nullable NSZone *)zone{
          return self;
      }
    
  • 命令:
    行为参数化
    降低代码重合度

      //命令模式代码示例Command命令、CommandManager命令管理者
    
      #import <Foundation/Foundation.h>
    
      @class Command;
      typedef void(^CommandCompletionCallBack)(Command* cmd);
    
      @interface Command : NSObject
      @property (nonatomic, copy) CommandCompletionCallBack completion;
      - (void)execute;//执行
      - (void)cancel;//取消
      - (void)done;//完成
      @end
    
      #import "Command.h"
      #import "CommandManager.h"
      @implementation Command
    
      - (void)execute{
          //写要做的事
          [self done];
      }
      - (void)cancel{
          self.completion = nil;//取消回调block
      }
      - (void)done
      {
          dispatch_async(dispatch_get_main_queue(), ^{
              //block回调
              if (_completion) {
                  _completion(self);
              }
              //释放
              self.completion = nil;
              //在任务管理者里面移除本次命令
              [[CommandManager sharedInstance].arrayCommands removeObject:self];
          });
      }
      @end
    
      #import <Foundation/Foundation.h>
      #import "Command.h"
      @interface CommandManager : NSObject
      // 命令管理容器
      @property (nonatomic, strong) NSMutableArray <Command*> *arrayCommands;
    
      // 命令管理者以单例方式呈现
      + (instancetype)sharedInstance;
      // 执行命令
      + (void)executeCommand:(Command *)cmd completion:(CommandCompletionCallBack)completion;
      // 取消命令
      + (void)cancelCommand:(Command *)cmd;
      @end
    
      #import "CommandManager.h"
      @implementation CommandManager
    
      // 命令管理者以单例方式呈现
      + (instancetype)sharedInstance
      {
          static CommandManager *instance = nil;
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
              instance = [[super allocWithZone:NULL] init];
          });
          return instance;
      }
      // 【必不可少】
      + (id)allocWithZone:(struct _NSZone *)zone{
          return [self sharedInstance];
      }
      // 【必不可少】
      - (id)copyWithZone:(nullable NSZone *)zone{
          return self;
      }
      // 初始化方法
      - (id)init
      {
          self = [super init];
          if (self) {
              // 初始化命令容器
              _arrayCommands = [NSMutableArray array];
          }
          return self;
      }
      // 添加命令
      + (void)executeCommand:(Command *)cmd completion:(CommandCompletionCallBack)completion
      {
          if (cmd) {
              // 如果命令正在执行不做处理,否则添加并执行命令
              if (![self _isExecutingCommand:cmd]) {
                  // 添加到命令容器当中
                  [[[self sharedInstance] arrayCommands] addObject:cmd];
                  // 设置命令执行完成的回调
                  cmd.completion = completion;
                  //执行命令
                  [cmd execute];
              }
          }
      }
    
      // 取消命令
      + (void)cancelCommand:(Command *)cmd
      {
          if (cmd) {
              // 从命令容器当中移除
              [[[self sharedInstance] arrayCommands] removeObject:cmd];
              // 取消命令执行
              [cmd cancel];
          }
      }
    
      // 判断当前命令是否正在执行
      + (BOOL)_isExecutingCommand:(Command *)cmd
      {
          if (cmd) {
              NSArray *cmds = [[self sharedInstance] arrayCommands];
              for (Command *aCmd in cmds) {
                  // 当前命令正在执行
                  if (cmd == aCmd) {
                      return YES;
                  }
              }
          }
          return NO;
      }
      @end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352