iOS 開發(fā)中的模式

在了解設計模式之前先了解下設計時的原則;

1. 設計原則

1.1 單一職責原則; 一個類只負責一個功能;
UIViewCALayer的關系;這篇文章結尾
1.2 開閉原則; 對修改關閉, 對擴展開放;
后期迭代類, 函數(shù), 功能模塊時盡量不去更改, 而是通過繼承和合成復用方式解決問題;
1.3 接口隔離原則; 將協(xié)議細分為多個專門的協(xié)議, 而不是一個龐大的多功能協(xié)議;
UITableViewdataSourcedelegate的模式, 一個負責數(shù)據(jù)一個負責處理代理回調;
1.4 依賴倒置原則; 抽象內(nèi)容不應該依賴具體實現(xiàn), 具體實現(xiàn)可以依賴于抽象;
1.5 里氏替換原則; 父類可以被子類無縫替換, 且原有功能不受影響;
KVO的實現(xiàn)過程, 中系統(tǒng)自動創(chuàng)建NSKVONotifying_子類替換原有類進而實現(xiàn)功能;
1.6 迪米特法則; 一個對象應該盡量少的去處理管理其他對象;
實現(xiàn)高內(nèi)聚低耦合;模塊之間的解耦;
1.7 合成復用原則; 盡量使用對象組合來達到復用的目的, 而不是繼承;
繼承時一旦基類發(fā)生變化, 那么他的派生類都會跟著變化;RXSwift中有才采用這種策略;


2. 設計模式

2.1 責任鏈模式;

責任鏈模式當主要思想是對象引用同一個類型的另一個對象; 每個對象的實現(xiàn)方法都一樣, 這樣可以形成一種模式就是如果當前對象不處理這個任務, 就把他拋給鏈上的另一個對象;實現(xiàn)方式有繼承自我實現(xiàn)(next指針)?等方式;
Cocoa中的經(jīng)典用法就是UI的響應鏈;
優(yōu)點:

  • 1.解耦請求的發(fā)送者和處理者;
  • 2.簡化對象, 不需要關心結構;
  • 3.鏈內(nèi)的成員可以隨時增減;

缺點:

  • 1.出現(xiàn)問題調試較為麻煩;
  • 2.任務并不一定保證能能被處理掉;

責任鏈實現(xiàn)的代碼講解:

#鏈條開始的類

#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;

///各個業(yè)務在該方法中做實際的處理事宜
- (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 {
            ///當前不處理, 沿著責任鏈, 指派給下一個業(yè)務處理
            if (self.nextHandler) {
                [self.nextHandler handle:resultB taskType:type];
            }else {
                ///沒有處理者, 傳為nil
                resultB(nil, NO);
            }
        }
    };
    ///當前業(yè)務進行處理
    [self handleBusiess:successB taskType:type];
}
- (void)handleBusiess:(HandleSuccess)callB taskType:(NSInteger)type{
    if (type < 10) {
        ///執(zhí)行邏輯處理, 處理完成后回調
        callB(YES);
     }else {
        callB(NO);
     }
}
@end
#鏈條上的另一個響應者實現(xiàn), 繼承自鏈條開始的類

#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) {
        ///執(zhí)行邏輯處理, 處理完成后回調
        callB(YES);
     }else {
        callB(NO);
     }
}

@end

實際運用:

- (void)responsiblityChain {
    ///這個數(shù)組作用是: 模擬一系列需要處理的任務
    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];
    ///創(chuàng)建一個責任鏈, 如果當前模型不處理, 就把任務向鏈中的下一個模型拋
    taskModel.nextHandler = taskModelA;
    taskModelA.nextHandler = taskModelB;
    taskModelB.nextHandler = taskModelC;

    ///模擬執(zhí)行多個任務
    for (NSNumber *taskNum in taskArr) {
        [taskModel handle:^(HandleModel *handler, BOOL handled) {
            NSLog(@"任務編號: %@ 執(zhí)行狀態(tài): %d   執(zhí)行者: %@", taskNum, handled, handler.class);
        } taskType:taskNum.integerValue];
    }
}

#執(zhí)行結果為
2019-05-05 16:10:26.395055+0800 DesignMode[7894:497216] 任務編號: 1 執(zhí)行狀態(tài): 1   執(zhí)行者: HandleModel
2019-05-05 16:10:26.395261+0800 DesignMode[7894:497216] 任務編號: 3 執(zhí)行狀態(tài): 1   執(zhí)行者: HandleModel
2019-05-05 16:10:26.395370+0800 DesignMode[7894:497216] 任務編號: 11 執(zhí)行狀態(tài): 1   執(zhí)行者: HandleModelA
2019-05-05 16:10:26.395509+0800 DesignMode[7894:497216] 任務編號: 15 執(zhí)行狀態(tài): 1   執(zhí)行者: HandleModelA
2019-05-05 16:10:26.395654+0800 DesignMode[7894:497216] 任務編號: 45 執(zhí)行狀態(tài): 1   執(zhí)行者: HandleModelC
2019-05-05 16:10:26.395768+0800 DesignMode[7894:497216] 任務編號: 23 執(zhí)行狀態(tài): 1   執(zhí)行者: HandleModelB
2019-05-05 16:10:26.395895+0800 DesignMode[7894:497216] 任務編號: 80 執(zhí)行狀態(tài): 0   執(zhí)行者: (null)
2019-05-05 16:10:26.396014+0800 DesignMode[7894:497216] 任務編號: 24 執(zhí)行狀態(tài): 1   執(zhí)行者: HandleModelB
2019-05-05 16:10:26.396124+0800 DesignMode[7894:497216] 任務編號: 66 執(zhí)行狀態(tài): 0   執(zhí)行者: (null)

責任鏈-示例代碼

2.2 橋接模式;

應用場景, 一個VC要適配多套數(shù)據(jù)模型時; 使用橋接模式能優(yōu)化處理;

橋接模式的結構示例

代碼講解示例

#抽象業(yè)務類持有屬性抽象數(shù)據(jù)請求類

#import <Foundation/Foundation.h>
#import "RequestModel.h"

NS_ASSUME_NONNULL_BEGIN
@interface BusiessModel : NSObject
///橋接模式的核心實現(xiàn), 抽象類持有;
@property (nonatomic, strong) RequestModel *requestModel;

///處理業(yè)務
- (void)handleTask;

@end
NS_ASSUME_NONNULL_END


#.m實現(xiàn)
#import "BusiessModel.h"

@implementation BusiessModel

/**
 具體實現(xiàn)的時候會有四種組合去處理業(yè)務
 BusinessA ---> Request1   Request2
 BusinessB ---> Request1   Request2
 */
- (void)handleTask {
    [self.requestModel requestData];
}

@end
#請求類的實例

#import "RequestModel.h"

NS_ASSUME_NONNULL_BEGIN
@interface Request1 : RequestModel

///實例實現(xiàn)
- (void)requestData;

@end
NS_ASSUME_NONNULL_END


#.m實現(xiàn)
#import "Request1.h"

@implementation Request1

- (void)requestData {
    NSLog(@"獲取數(shù)據(jù)2");
}


@end
#業(yè)務類的實例過程
#import "BusiessModel.h"

NS_ASSUME_NONNULL_BEGIN
@interface BusiessA : BusiessModel

///實例實現(xiàn)
- (void)handleTask;

@end
NS_ASSUME_NONNULL_END


#.m實現(xiàn)
#import "BusiessA.h"
@implementation BusiessA

- (void)handleTask {
    ///在調用父類之前可以處理一些邏輯;
    
    ///調用父類實現(xiàn)
    [super handleTask];
    
    ///在調用父類之后仍然可以處理一些邏輯;
}
@end
///橋接模式
- (void)bridge {
    ///根據(jù)業(yè)務情形選擇使用BusiessA或者BusiessB
    BusiessModel *businessM = [[BusiessA alloc] init];
    ///根據(jù)業(yè)務情形選擇使用Request1或者Request2
    RequestModel *requestM = [[Request2 alloc] init];
    ///抽象類的邏輯實例實現(xiàn)
    businessM.requestModel = requestM;
    ///真正處理業(yè)務
    [businessM handleTask];
}

橋接-示例代碼

2.3 適配器模式;

適用場景: 工程中的年代很久遠的類, 并且邏輯已經(jīng)很成熟, 基本上沒什么問題, 如果要對其更改或者擴展, 直接更改是不合適的, 這時通過適配器模式就行擴展比較合適;
代碼講解示例

#一個年代很久遠的類, 功能邏輯已經(jīng)很完善;
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RemoteModel : NSObject

///這個類的其中一個功能, 已經(jīng)相對很完善
- (void)operationTask;

@end
NS_ASSUME_NONNULL_END

#.m實現(xiàn)
#import "RemoteModel.h"
@implementation RemoteModel

///這個類的其中一個功能, 已經(jīng)相對很完善
- (void)operationTask {
    NSLog(@"處理一些邏輯");
}

@end

對其原先邏輯進行擴展


#import <Foundation/Foundation.h>
#import "RemoteModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface NowModel : NSObject

/**
 現(xiàn)在想對RemoteModel中 - (void)operationTask; 方法進行添加一些新的邏輯;
 因為原來的邏輯已經(jīng)很完整,完善; 通過適配器模式進行擴展;
 */
@property (nonatomic, strong) RemoteModel   *remoteM;
///對原先邏輯進行擴展
- (void)nowOperationTask;

@end
NS_ASSUME_NONNULL_END

#.m實現(xiàn)
#import "NowModel.h"
@implementation NowModel

///對原先邏輯進行擴展
- (void)nowOperationTask {
    NSLog(@"先執(zhí)行添加的新邏輯");
    ///然后執(zhí)行原先的邏輯
    [self.remoteM operationTask];
    NSLog(@"然后執(zhí)行一些補充的新邏輯");
}

@end
///適配器模式
- (void)adapter {
    RemoteModel *remoteModel = [[RemoteModel alloc] init];
    NowModel *nowModel = [[NowModel alloc] init];
    nowM.remoteM = remoteModel;
    [nowModel nowOperationTask];
}

適配器-示例代碼

2.4 單例模式;

使用場景, 工程中一些常用的邏輯可以放在單例中, 這樣可以快速獲取到; 因為單例整個生命周期只會創(chuàng)建一次, 節(jié)省資源;

代碼示例講解

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN
///遵循這兩個協(xié)議是為了防止無意中進行了copy或mutableCopy而開辟新地址;
@interface GlobalModel : NSObject<NSCopying, NSMutableCopying>

+ (GlobalModel *)share;

@end
NS_ASSUME_NONNULL_END



#.m實現(xiàn)
#import "GlobalModel.h"
@implementation GlobalModel

+ (GlobalModel *)share {
    static GlobalModel * model = nil;
    ///確保只能執(zhí)行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        ///為什么不能用self進行alloc, 因為重寫下面的方法中返回了[self share]會造成循環(huán);
        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始終是同一塊內(nèi)存地址

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 設計模式詳解

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容