第11章:設計模式

一、六大設計原則

     1、單一職責原則

一個類只負責一件事

     2、依賴倒置原則

抽象不應該依賴於具體實現,具體實現可以依賴於抽象。

     3、開放-關閉原則

對修改關閉,對擴展開放。比如常見的就是可繼承,不可修改。

     4、里氏替換原則

父類可以被子類無縫替換,且原有功能不受任何影響。比如kvo的實現。

     5、接口隔離原則

使用多個專門協議、而不是一個龐大臃腫的協議,且協議中的方法應該儘量少。比如tableview的delegate、datasource

     6、迪米特法則

一個對象應該對其他對象有儘可能少的瞭解。這樣就能做到高內聚、低耦合。

 

二、責任鏈模式

     1、首先看一個需求變更問題:原來業務的調用順序是“業務A”=>“業務B”=>“業務C”,突然產品經理要求變成“業務C”=>“業務B”=>“業務A”,如何從技術的角度來動態調整以應對這種變化呢?使用責任鏈模式可以實現動態下發,這就解決了這個調用順序動態調整問題。

     2、責任鏈的類構成:其實就是類A中有一個成員變量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;
// 響應者的處理方法==我理解的是:這個函數由調用者調用,傳入的block是調用者想要在業務處理完成時執行的動作,動作處理完成時會給handler和handled這兩個參數來告訴block最後是誰處理的、是否處理完成
- (void)handle:(ResultBlock)result;

// 各個業務在該方法當中做實際業務處理==我理解的是:這個函數不應該對外公開,因爲其由handle:調用,並且completion在handle:中也有固定的邏輯,如果外部調用的話handle:函數豈不是一點用處都沒有,是個擺設!
- (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
{
    /*
     業務邏輯處理,如網絡請求、本地照片查詢等
     */
}
@end

 

三、橋接模式

     1、何爲橋接模式?我理解的就是:建立類A和類B之間的一個依賴關係,不管類A的子類和類B的子類是如何組合的,他們都是建立在“類A和類B依賴關係”之上的,不需要再次建立依賴關係,最多隻是建立新需求需要的新的A、B的子類。類關係圖如下:

     代碼說明如下:

@interface BaseObjectA : NSObject
		// 橋接模式的核心實現
		@property (nonatomic, strong) BaseObjectB *objB;
		// 獲取數據
		- (void)handle;
		@end
		@implementation BaseObjectA
		- (void)handle
		{
		    // override to subclass
		    [self.objB fetchData];
		}
		@end

		@interface BaseObjectB : NSObject
		- (void)fetchData;
		@end
		@implementation BaseObjectB
		- (void)fetchData
		{
		    // override to subclass
		}
		@end

		//demo中調用代碼如下
		// 創建一個具體的ClassA
    		_objA = [[ObjectA1 alloc] init];
    		// 創建一個具體的ClassB
    		BaseObjectB *b1 = [[ObjectB1 alloc] init];
    		// 將一個具體的ClassB1 指定給抽象的ClassB
    		_objA.objB = b1;
    		// 獲取數據
    		[_objA handle];

     2、看一個業務解耦面試問題:一個列表上有三套網絡數據,且列表在不同的地方使用的是不同的數據,那麼設計來解耦“列表、數據”的對應關係呢,使得組合變更時業務以來邏輯動態適應?使用橋接模式即可。

 

四、適配器模式

     1、面試問題:一個現有類需要適應變化該怎麼做?適配器模式解決。

     2、適配器分類

1)、對象適配器:比較常見。其類構成如下:

     “適配對象”的某個成員變量爲“被適配對象”。適配對象將被適配對象適配後對外提供服務。

2)、類適配器

 

五、單例模式

     主要考察初中級人員。這個模式大家都會用,但是很多人不一定使用的完全正確。單例模式一定要會手寫,完整的代碼和注意事項如下:

@implementation Mooc
+ (id)sharedInstance
{
    // 靜態局部變量
    static Mooc *instance = nil;
    
    // 通過dispatch_once方式 確保instance在多線程環境下只被創建一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 創建實例==此處通過super調用,因爲此處用self的話,如果有人使用allocWithZone創建實例就會造成循環引用
        instance = [[super allocWithZone:NULL] init];
    });
    return instance;
}
// 重寫方法【必不可少==原因是防止用戶通過allocWithZone創建對象,而不使用單例】
+ (id)allocWithZone:(struct _NSZone *)zone{
    return [self sharedInstance];
}
// 重寫方法【必不可少==原因是防止用戶通過copyWithZone copy單例對象來創建對象,而不使用單例】
- (id)copyWithZone:(nullable NSZone *)zone{
    return self;
}
@end

 

六、命令模式

     命令模式是對行爲進行參數化的一種設計模式,其作用是降低代碼重合度。比如微博中很多頁面都有“轉發、評論、贊”,這三個操作就可以封裝爲命令模式,在不同的頁面點擊按鈕時觸發命令。代碼如下:

#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{
    //override to subclass;
    [self done];
}
- (void)cancel{
    self.completion = nil;
}
- (void)done
{
    dispatch_async(dispatch_get_main_queue(), ^{
        if (_completion) {
            _completion(self);
        }
        //釋放
        self.completion = nil;
        [CommandManager removeCommand:self];
    });
}
@end
#import <Foundation/Foundation.h>
#import "Command.h"
@interface CommandManager : NSObject
// 命令執行完成後從管理器中刪除
+ (void)removeCommand:(Command *)cmd;
// 命令管理者以單例方式呈現
+ (instancetype)sharedInstance;
// 執行命令
+ (void)executeCommand:(Command *)cmd completion:(CommandCompletionCallBack)completion;
// 取消命令
+ (void)cancelCommand:(Command *)cmd;
@end
#import "CommandManager.h"
@interface CommandManager()
// 命令管理容器
@property (nonatomic, strong) NSMutableArray <Command*> *arrayCommands;
@end
@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;
}
// 命令執行完成後從管理器中刪除
+ (void)removeCommand:(Command *)cmd
{
    if (cmd) {
        // 從命令容器當中移除
        [[[self sharedInstance] arrayCommands] removeObject:cmd];
        // 取消命令執行
        [cmd cancel];
    }
}
@end

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章