知识点总结

iOS 开发中的模式

2019-04-30  本文已影响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的响应链;
优点:

缺点:

责任链实现的代码讲解:

#链条开始的类

#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 设计模式详解

上一篇下一篇

猜你喜欢

热点阅读