一、六大設計原則
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