美文网首页知识点总结
iOS 开发中的模式

iOS 开发中的模式

作者: 飞不越疯人院 | 来源:发表于2019-04-30 14:07 被阅读5次

    在了解设计模式之前先了解下设计时的原则;

    1. 设计原则

    1.1 单一职责原则; 一个类只负责一个功能;
    UIViewCALayer的关系;这篇文章结尾
    1.2 开闭原则; 对修改关闭, 对扩展开放;
    后期迭代类, 函数, 功能模块时尽量不去更改, 而是通过继承和合成复用方式解决问题;
    1.3 接口隔离原则; 将协议细分为多个专门的协议, 而不是一个庞大的多功能协议;
    UITableViewdataSourcedelegate的模式, 一个负责数据一个负责处理代理回调;
    1.4 依赖倒置原则; 抽象内容不应该依赖具体实现, 具体实现可以依赖于抽象;
    1.5 里氏替换原则; 父类可以被子类无缝替换, 且原有功能不受影响;
    KVO的实现过程, 中系统自动创建NSKVONotifying_子类替换原有类进而实现功能;
    1.6 迪米特法则; 一个对象应该尽量少的去处理管理其他对象;
    实现高内聚低耦合;模块之间的解耦;
    1.7 合成复用原则; 尽量使用对象组合来达到复用的目的, 而不是继承;
    继承时一旦基类发生变化, 那么他的派生类都会跟着变化;RXSwift中有才采用这种策略;


    2. 设计模式

    2.1 责任链模式;

    责任链模式当主要思想是对象引用同一个类型的另一个对象; 每个对象的实现方法都一样, 这样可以形成一种模式就是如果当前对象不处理这个任务, 就把他抛给链上的另一个对象;实现方式有继承自我实现(next指针)?等方式;
    Cocoa中的经典用法就是UI的响应链;
    优点:

    • 1.解耦请求的发送者和处理者;
    • 2.简化对象, 不需要关心结构;
    • 3.链内的成员可以随时增减;

    缺点:

    • 1.出现问题调试较为麻烦;
    • 2.任务并不一定保证能能被处理掉;

    责任链实现的代码讲解:

    #链条开始的类
    
    #import <Foundation/Foundation.h>
    @class HandleModel;
    typedef void(^HandleSuccess)(BOOL handled);
    typedef void(^HanleResult)(HandleModel * _Nullable handler, BOOL handled);
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface HandleModel : NSObject
    ///下一个响应者, 构成响应链的关键
    @property (nonatomic, strong) HandleModel   *nextHandler;
    //响应者的处理方法
    - (void)handle:(HanleResult)resultB taskType:(NSInteger)type;
    
    ///各个业务在该方法中做实际的处理事宜
    - (void)handleBusiess:(HandleSuccess)callB taskType:(NSInteger)type;
    @end
    NS_ASSUME_NONNULL_END
    
    
    #import "HandleModel.h"
    @implementation HandleModel
    ///责任链入口方法, 如果当前类不处理就向链条的下一个指派
    - (void)handle:(HanleResult)resultB taskType:(NSInteger)type{
        HandleSuccess successB = ^(BOOL success){
            if (success) {
                resultB(self, success);
            }else {
                ///当前不处理, 沿着责任链, 指派给下一个业务处理
                if (self.nextHandler) {
                    [self.nextHandler handle:resultB taskType:type];
                }else {
                    ///没有处理者, 传为nil
                    resultB(nil, NO);
                }
            }
        };
        ///当前业务进行处理
        [self handleBusiess:successB taskType:type];
    }
    - (void)handleBusiess:(HandleSuccess)callB taskType:(NSInteger)type{
        if (type < 10) {
            ///执行逻辑处理, 处理完成后回调
            callB(YES);
         }else {
            callB(NO);
         }
    }
    @end
    
    #链条上的另一个响应者实现, 继承自链条开始的类
    
    #import "HandleModel.h"
    
    NS_ASSUME_NONNULL_BEGIN
    @interface HandleModelA : HandleModel
    
    @end
    NS_ASSUME_NONNULL_END
    
    #import "HandleModelA.h"
    @implementation HandleModelA
    
    //这个方法继承自父类, 逻辑不需变动, 如果当前类不处理就向链条的下一个指派
    //- (void)handle:(HanleResult)resultB taskType:(NSInteger)type {
    //    HandleSuccess successB = ^(BOOL success){
    //        if (success) {
    //            resultB(self, YES);
    //        }else {
    //            if (self.nextHandler) {
    //                [self.nextHandler handle:resultB taskType:type];
    //            }else {
    //                resultB(nil, NO);
    //            }
    //        }
    //    };
    //    [self handleBusiess:successB taskType:type];
    //}
    
    - (void)handleBusiess:(HandleSuccess)callB taskType:(NSInteger)type{
        if (type >= 10 && type < 20) {
            ///执行逻辑处理, 处理完成后回调
            callB(YES);
         }else {
            callB(NO);
         }
    }
    
    @end
    

    实际运用:

    - (void)responsiblityChain {
        ///这个数组作用是: 模拟一系列需要处理的任务
        NSArray *taskArr = @[@(1), @(3), @(11), @(15), @(45), @(23), @(80), @(24), @(66)];
        HandleModel *taskModel = [[HandleModel alloc] init];
        HandleModel *taskModelA = [[HandleModelA alloc] init];
        HandleModel *taskModelB = [[HandleModelB alloc] init];
        HandleModel *taskModelC = [[HandleModelC alloc] init];
        ///创建一个责任链, 如果当前模型不处理, 就把任务向链中的下一个模型抛
        taskModel.nextHandler = taskModelA;
        taskModelA.nextHandler = taskModelB;
        taskModelB.nextHandler = taskModelC;
    
        ///模拟执行多个任务
        for (NSNumber *taskNum in taskArr) {
            [taskModel handle:^(HandleModel *handler, BOOL handled) {
                NSLog(@"任务编号: %@ 执行状态: %d   执行者: %@", taskNum, handled, handler.class);
            } taskType:taskNum.integerValue];
        }
    }
    
    #执行结果为
    2019-05-05 16:10:26.395055+0800 DesignMode[7894:497216] 任务编号: 1 执行状态: 1   执行者: HandleModel
    2019-05-05 16:10:26.395261+0800 DesignMode[7894:497216] 任务编号: 3 执行状态: 1   执行者: HandleModel
    2019-05-05 16:10:26.395370+0800 DesignMode[7894:497216] 任务编号: 11 执行状态: 1   执行者: HandleModelA
    2019-05-05 16:10:26.395509+0800 DesignMode[7894:497216] 任务编号: 15 执行状态: 1   执行者: HandleModelA
    2019-05-05 16:10:26.395654+0800 DesignMode[7894:497216] 任务编号: 45 执行状态: 1   执行者: HandleModelC
    2019-05-05 16:10:26.395768+0800 DesignMode[7894:497216] 任务编号: 23 执行状态: 1   执行者: HandleModelB
    2019-05-05 16:10:26.395895+0800 DesignMode[7894:497216] 任务编号: 80 执行状态: 0   执行者: (null)
    2019-05-05 16:10:26.396014+0800 DesignMode[7894:497216] 任务编号: 24 执行状态: 1   执行者: HandleModelB
    2019-05-05 16:10:26.396124+0800 DesignMode[7894:497216] 任务编号: 66 执行状态: 0   执行者: (null)
    
    

    责任链-示例代码

    2.2 桥接模式;

    应用场景, 一个VC要适配多套数据模型时; 使用桥接模式能优化处理;

    桥接模式的结构示例

    代码讲解示例

    #抽象业务类持有属性抽象数据请求类
    
    #import <Foundation/Foundation.h>
    #import "RequestModel.h"
    
    NS_ASSUME_NONNULL_BEGIN
    @interface BusiessModel : NSObject
    ///桥接模式的核心实现, 抽象类持有;
    @property (nonatomic, strong) RequestModel *requestModel;
    
    ///处理业务
    - (void)handleTask;
    
    @end
    NS_ASSUME_NONNULL_END
    
    
    #.m实现
    #import "BusiessModel.h"
    
    @implementation BusiessModel
    
    /**
     具体实现的时候会有四种组合去处理业务
     BusinessA ---> Request1   Request2
     BusinessB ---> Request1   Request2
     */
    - (void)handleTask {
        [self.requestModel requestData];
    }
    
    @end
    
    #请求类的实例
    
    #import "RequestModel.h"
    
    NS_ASSUME_NONNULL_BEGIN
    @interface Request1 : RequestModel
    
    ///实例实现
    - (void)requestData;
    
    @end
    NS_ASSUME_NONNULL_END
    
    
    #.m实现
    #import "Request1.h"
    
    @implementation Request1
    
    - (void)requestData {
        NSLog(@"获取数据2");
    }
    
    
    @end
    
    #业务类的实例过程
    #import "BusiessModel.h"
    
    NS_ASSUME_NONNULL_BEGIN
    @interface BusiessA : BusiessModel
    
    ///实例实现
    - (void)handleTask;
    
    @end
    NS_ASSUME_NONNULL_END
    
    
    #.m实现
    #import "BusiessA.h"
    @implementation BusiessA
    
    - (void)handleTask {
        ///在调用父类之前可以处理一些逻辑;
        
        ///调用父类实现
        [super handleTask];
        
        ///在调用父类之后仍然可以处理一些逻辑;
    }
    @end
    
    ///桥接模式
    - (void)bridge {
        ///根据业务情形选择使用BusiessA或者BusiessB
        BusiessModel *businessM = [[BusiessA alloc] init];
        ///根据业务情形选择使用Request1或者Request2
        RequestModel *requestM = [[Request2 alloc] init];
        ///抽象类的逻辑实例实现
        businessM.requestModel = requestM;
        ///真正处理业务
        [businessM handleTask];
    }
    

    桥接-示例代码

    2.3 适配器模式;

    适用场景: 工程中的年代很久远的类, 并且逻辑已经很成熟, 基本上没什么问题, 如果要对其更改或者扩展, 直接更改是不合适的, 这时通过适配器模式就行扩展比较合适;
    代码讲解示例

    #一个年代很久远的类, 功能逻辑已经很完善;
    #import <Foundation/Foundation.h>
    NS_ASSUME_NONNULL_BEGIN
    @interface RemoteModel : NSObject
    
    ///这个类的其中一个功能, 已经相对很完善
    - (void)operationTask;
    
    @end
    NS_ASSUME_NONNULL_END
    
    #.m实现
    #import "RemoteModel.h"
    @implementation RemoteModel
    
    ///这个类的其中一个功能, 已经相对很完善
    - (void)operationTask {
        NSLog(@"处理一些逻辑");
    }
    
    @end
    

    对其原先逻辑进行扩展

    
    #import <Foundation/Foundation.h>
    #import "RemoteModel.h"
    NS_ASSUME_NONNULL_BEGIN
    @interface NowModel : NSObject
    
    /**
     现在想对RemoteModel中 - (void)operationTask; 方法进行添加一些新的逻辑;
     因为原来的逻辑已经很完整,完善; 通过适配器模式进行扩展;
     */
    @property (nonatomic, strong) RemoteModel   *remoteM;
    ///对原先逻辑进行扩展
    - (void)nowOperationTask;
    
    @end
    NS_ASSUME_NONNULL_END
    
    #.m实现
    #import "NowModel.h"
    @implementation NowModel
    
    ///对原先逻辑进行扩展
    - (void)nowOperationTask {
        NSLog(@"先执行添加的新逻辑");
        ///然后执行原先的逻辑
        [self.remoteM operationTask];
        NSLog(@"然后执行一些补充的新逻辑");
    }
    
    @end
    
    ///适配器模式
    - (void)adapter {
        RemoteModel *remoteModel = [[RemoteModel alloc] init];
        NowModel *nowModel = [[NowModel alloc] init];
        nowM.remoteM = remoteModel;
        [nowModel nowOperationTask];
    }
    

    适配器-示例代码

    2.4 单例模式;

    使用场景, 工程中一些常用的逻辑可以放在单例中, 这样可以快速获取到; 因为单例整个生命周期只会创建一次, 节省资源;

    代码示例讲解

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    ///遵循这两个协议是为了防止无意中进行了copy或mutableCopy而开辟新地址;
    @interface GlobalModel : NSObject<NSCopying, NSMutableCopying>
    
    + (GlobalModel *)share;
    
    @end
    NS_ASSUME_NONNULL_END
    
    
    
    #.m实现
    #import "GlobalModel.h"
    @implementation GlobalModel
    
    + (GlobalModel *)share {
        static GlobalModel * model = nil;
        ///确保只能执行一次
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            ///为什么不能用self进行alloc, 因为重写下面的方法中返回了[self share]会造成循环;
            model = [[super allocWithZone:NULL] init];
        });
        return model;
    }
    
    ///确保多次alloc也是同一块地址
    + (instancetype)allocWithZone:(struct _NSZone *)zone {
        return [self share];
    }
    
    ///确保即使进行copy了也是同一块地址
    - (id)copyWithZone:(NSZone *)zone {
        return  self;
    }
    
    ///确保即使进行mutableCopy了也是同一块地址
    - (id)mutableCopyWithZone:(NSZone *)zone {
        return self;
    }
    @end
    
    
    ///单例模式
    - (void)singleton {
        GlobalModel *model = [[GlobalModel alloc] init];
        GlobalModel *model1 = [[GlobalModel alloc] init];
        GlobalModel *model2 = [model copy];
        GlobalModel *model3 = [model mutableCopy];
        GlobalModel *model4 = [GlobalModel share];
        NSLog(@"model地址:   %@", model);
        NSLog(@"model1地址1: %@", model1);
        NSLog(@"model2地址2: %@", model2);
        NSLog(@"model3地址3: %@", model3);
        NSLog(@"model4地址4: %@", model4);
    }
    #不论是几次alloc或者copy, mutableCopy始终是同一块内存地址
    
    2019-05-06 17:19:42.822105+0800 DesignMode[13036:251989] model地址:   <GlobalModel: 0x60000174c020>
    2019-05-06 17:19:42.822246+0800 DesignMode[13036:251989] model1地址1: <GlobalModel: 0x60000174c020>
    2019-05-06 17:19:42.822400+0800 DesignMode[13036:251989] model2地址2: <GlobalModel: 0x60000174c020>
    2019-05-06 17:19:42.822511+0800 DesignMode[13036:251989] model3地址3: <GlobalModel: 0x60000174c020>
    2019-05-06 17:19:42.822599+0800 DesignMode[13036:251989] model4地址4: <GlobalModel: 0x60000174c020>
    

    单例-示例代码



    参考文章
    推荐 面向对象设计原则概述
    面向对象设计原则之单一职责原则
    面向对象设计原则之开闭原则
    面向对象设计原则之接口隔离原则
    面向对象设计原则之依赖倒置原则
    面向对象设计原则之里氏替换原则
    面向对象设计原则之迪米特法则
    面向对象设计原则之合成复用原则
    iOS 设计模式详解

    相关文章

      网友评论

        本文标题:iOS 开发中的模式

        本文链接:https://www.haomeiwen.com/subject/oevmnqtx.html