設(shè)計(jì)模式即編碼的工程化歉甚,是代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)皂吮。使用設(shè)計(jì)模式可提高代碼的復(fù)用性筋夏、可讀性和可靠性蒂胞。設(shè)計(jì)模式在各類面向?qū)ο蟮恼Z言中基本相通,僅在具體的實(shí)現(xiàn)語法上略有差異条篷,下面我們以O(shè)C為例來理解和研究一些常用的設(shè)計(jì)模式骗随。
單例模式
保證程序運(yùn)行中,一個(gè)類全局只有一個(gè)實(shí)例赴叹。它提供了對(duì)類對(duì)象的全局訪問點(diǎn)鸿染,在整個(gè)過程中共享著一份資源。
應(yīng)用:登錄控制體系稚瘾、網(wǎng)絡(luò)請(qǐng)求牡昆、音樂播放、分享體系等摊欠。
+ (instancetype)sharedInstance {
? ? ? static Singleton *singleton = nil;
? ? ? static dispatch_once_t onceToken;
? ? ? dispatch_once(&onceToken, ^{
? ? ? ? ? ? singleton = [[Singleton alloc] init];
? ? ? });
? ? ? return singleton;?
}
//嚴(yán)謹(jǐn)情況下應(yīng)把copyWithZone和mutableCopyWithZone也重寫
注:可將allocWithZone重寫為dispatch_once實(shí)現(xiàn)單例丢烘,sharedInstance中調(diào)用默認(rèn)的alloc init(alloc會(huì)默認(rèn)調(diào)用allocWithZone),此時(shí)些椒,單例可被繼承播瞳,重寫init方法實(shí)現(xiàn)子單例的擴(kuò)展。如下:
static Singleton *_instance;
+ (id)allocWithZone:(struct _NSZone *)zone {
? ? ? static dispatch_once_t onceToken;
? ? ? dispatch_once(&onceToken, ^{
? ? ? ? ? ? _instance = [super allocWithZone:zone];
? ? ? )};
? ? ? return _instance;
}
+ (instancetype)sharedInstance {
? ? ? ?if(!_instance) {
? ? ? ? ? ? ?_instance = [[Singleton alloc] init];
? ? ? ? }
? ? ? ? return _instance;
}
使用帶參數(shù)的宏定義可以把單例模式的聲明優(yōu)化到只寫一次免糕,在各單例類中的.h赢乓、.m中只需調(diào)用宏定義即可。
最后補(bǔ)充一下iOS系統(tǒng)的單例類:UIApplication石窑,UIScreen牌芋,NSNotificationCenter,NSFileManager松逊,NSUserDefaults躺屁,NSURLCache,NSHTTPCookieStorage等经宏。
工廠模式
簡單工廠模式
一個(gè)工廠類犀暑,根據(jù)傳入?yún)?shù)不同,決定初始化某個(gè)具體產(chǎn)品實(shí)例烁兰。
應(yīng)用理解:一個(gè)簡單四則運(yùn)算計(jì)算器耐亏。如果不使用工廠模式,要實(shí)現(xiàn)加減乘除四個(gè)方法就需要new4個(gè)運(yùn)算方法類沪斟,這顯然不是一個(gè)完美的解決方案广辰。此時(shí),若有個(gè)產(chǎn)品基類BaseCalculate,它包括加減乘除四個(gè)產(chǎn)品類(Add择吊,Minus袱耽,Multiply,Devide)干发,在需要實(shí)例化運(yùn)算對(duì)象的地方,使用運(yùn)算工廠類CalcuteFactory史翘,根據(jù)類型返回產(chǎn)品類的方法-(BaseCaculate *)createWithType:(id)type;生成對(duì)應(yīng)運(yùn)算的產(chǎn)品類對(duì)象枉长。
缺點(diǎn):增加或者修改產(chǎn)品類時(shí),需在代碼層次修改工廠類(此時(shí)需重新測(cè)試工廠類)琼讽,不夠靈活必峰,不便擴(kuò)展。
為解決上述缺點(diǎn)钻蹬,出現(xiàn)了第二種工廠模式:
工廠方法模式
一個(gè)工廠類吼蚁,一個(gè)產(chǎn)品類對(duì)應(yīng)一個(gè)工廠子類(產(chǎn)品與工廠配套),即问欠,擴(kuò)展產(chǎn)品類別時(shí)需同時(shí)擴(kuò)展工廠子類肝匆,與簡單工廠模式相比,抽象了工廠類顺献。工廠子類中重寫抽象工廠類中的方法生產(chǎn)對(duì)應(yīng)的產(chǎn)品子類旗国。
缺點(diǎn)顯而易見:大量的產(chǎn)品+工廠類,且產(chǎn)品和工廠間隔斷嚴(yán)重?zé)o法復(fù)用相同代碼注整。
于是抽象工廠模式應(yīng)運(yùn)而生:
抽象工廠模式
抽象工廠模式的最大特點(diǎn)就是有多個(gè)抽象產(chǎn)品類能曾。找出某類產(chǎn)品的共性,設(shè)計(jì)出此類產(chǎn)品的抽象類(派生出多個(gè)具體產(chǎn)品類)肿轨。而其具有一個(gè)抽象工廠類和多個(gè)具體工廠類寿冕,每個(gè)具體工廠類都可創(chuàng)建多個(gè)具體產(chǎn)品類。
觀察者模式
發(fā)布(publish)- 訂閱(Subscribe)模式椒袍,用于一對(duì)多依賴關(guān)系中的解耦驼唱。對(duì)象可以通過注冊(cè),成為觀察者(Observer)槐沼,去訂閱中心對(duì)象(Subject)的變化曙蒸。Subject(被觀察者)則需要實(shí)現(xiàn)觀察者注冊(cè)、數(shù)據(jù)更新通知岗钩、觀察者移除三個(gè)基礎(chǔ)方法纽窟。
NSNotification
注冊(cè)觀察者
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notice:) name:@"PostName" object:nil];
- (void)notice:(id)sender { NSLog(@"%@",sender); }
被觀察者發(fā)出通知
[[NSNotificationCenterdefaultCenter] postNotificationName:@"PostName" object:nil];
移除通知
- (void)dealloc ?{
? ? ? [[NSNotificationCenter defaultCenter] removeObserver:self name:@"PostName" object:nil];
}
KVO
KVC、KVO小結(jié)和應(yīng)用
代理模式
OC和Swift中的protocol
非正式協(xié)議
即Category兼吓,如NSString (StringFrame)臂港。
代理與Block
1、block是讓代碼塊以閉包(一個(gè)函數(shù)+其執(zhí)行的外部上下文變量)的形式傳遞內(nèi)容,實(shí)在是太輕量級(jí)了审孽,適用于大多數(shù)異步和簡單的回調(diào)县袱。
2、當(dāng)有多個(gè)方法回調(diào)時(shí)應(yīng)當(dāng)選用delegate會(huì)更清晰佑力,如UITableView的delegate代理方法式散。
3、block會(huì)涉及到棧區(qū)到堆區(qū)的拷貝等操作打颤,delegate只是定義了一個(gè)方法列表暴拄,在遵守了協(xié)議的對(duì)象的objc_protocol_list中添加了一個(gè)節(jié)點(diǎn),運(yùn)行時(shí)向?qū)ο蟀l(fā)送消息即可编饺。所以block在時(shí)間空間消耗都大于delegate乖篷,性能消耗較大。
4透且、代理更加面向過程撕蔼,block更加面向結(jié)果。
策略模式
#結(jié)合現(xiàn)金支付計(jì)算策略實(shí)例詳細(xì)說明#
1秽誊、定義一個(gè)抽象的鲸沮、通用的算法(抽象策略類BaseStrategy)協(xié)議,此角色給出所有具體策略類所需的接口养距;
@protocol CashBase?
-(CGFloat)acceptCash:(CGFloat)cash;
@end
2诉探、讓每個(gè)具體算法(繼承Base的具體策略類NormalStrategy,SpecialStrategy)都遵循他的守則棍厌,提供了具體的算法實(shí)現(xiàn)了抽象策略類定義的接口肾胯;
@interface CashNormal : NSObject <CashBase>
@end
@implementation CashNormal
-(CGFloat)acceptCash:(CGFloat)cash { return cash; }
@end
@interface CaseReturn : NSObject <CashBase>
-(instancetype)initWithMoneyReturn:(CGFloat)moneyReturn;
@end
@implementation CaseReturn ? ??
-(instancetype)initWithMoneyReturn:(CGFloat)moneyReturn {
? ? ? if (self) {
? ? ? ? ? ?_moneyReturn = moneyReturn;
? ? ? }
? ? ? return self;
}
-(CGFloat)acceptCash:(CGFloat)cash {
? ? ? return cash - self.moneyReturn;
}
@end
3、然后需要定義一個(gè)環(huán)境角色(Context類)用來持有一個(gè)Strategy的引用耘纱,配合簡單工廠模式敬肚,根據(jù)入?yún)Q定調(diào)用哪個(gè)具體策略類算法;
@interface CashContext : NSObject
-(instancetype)initWithCashType:(CashType)type;
-(CGFloat)getResult:(CGFloat)money;
@end
@implementation CashContext
-(instancetype)initWithCashType:(CashType)type{
? ? ? //根據(jù)type初始化算法實(shí)例
}
-(CGFloat)getResult:(CGFloat)money{
? ? ? //算法實(shí)例調(diào)用策略接口
? ? ? return [self.cashSuper acceptCash:money];
}
@end
4束析、最后在需要的地方調(diào)用Context對(duì)象艳馒。
CashContext * context = [[CashContext alloc] initWithCashType:CashTypeNormal];
NSLog(@"結(jié)果是%f",[context getResult:100]);
裝飾模式
不修改原類代碼的情況下,動(dòng)態(tài)员寇、透明的給一個(gè)對(duì)象增加新的行為和職責(zé)弄慰,Decorator比生成子類更加靈活,其目的是把功能分散蝶锋,運(yùn)行期間再動(dòng)態(tài)組合陆爽。
裝飾器的構(gòu)成:1、Component扳缕,抽象的組件父類慌闭,聲明了一些方法由子類進(jìn)行重載别威;ConcreteComponent,具體的組件類驴剔,實(shí)現(xiàn)了組件接口省古,通常是被裝飾的原始對(duì)象。
2丧失、Decorator豺妓,裝飾器父類(Component細(xì)化后的抽象類),用來持有原對(duì)象(被裝飾對(duì)象)布讹。ConcreteDecorator具體的裝飾器類科侈,具體實(shí)現(xiàn)要添加的功能,并內(nèi)嵌Component操作炒事,以裝飾具體的組件對(duì)象。
在iOS中蔫慧,分類(category)簡單便捷的實(shí)現(xiàn)了裝飾器設(shè)計(jì)模式所能達(dá)到的功能挠乳,但嚴(yán)格意義上講并不符合裝飾器模式的定義。
注:1姑躲、有些教程中說委托也是iOS中的一種裝飾器模式睡扬,但我認(rèn)為委托沒有做到裝飾模式定義中“不修改原類代碼”的要求;2黍析、分類中定義的方法不要和原有類的方法重名卖怜。
軟件開發(fā)中還用很多常用的設(shè)計(jì)模式,如模板方法模式(提取算法可復(fù)用結(jié)構(gòu)阐枣,延遲某些特定步驟到子類:如問答題的不變部分(題目)和變化部分(答案))马靠、外觀模式(為一套需要同時(shí)調(diào)用的子系統(tǒng)定義一個(gè)高層的綜合接口,便于多個(gè)接口同時(shí)調(diào)用)蔼两、建造者模式甩鳄、狀態(tài)模式、適配器模式额划、備忘錄模式妙啃、組合模式、迭代器模式俊戳、單列模式揖赴、橋接模式、命令模式抑胎、職責(zé)鏈模式燥滑、中介者模式、享元模式圆恤、解釋器模式突倍、訪問者模式腔稀、原型模式(已有對(duì)象深拷貝申請(qǐng)新內(nèi)存,生成新對(duì)象羽历,需滿足NSCopying協(xié)議)等焊虏。
最后提供一下容易亂入的MVC,MVVM等設(shè)計(jì)模式等鏈接秕磷,嚴(yán)格來說诵闭,它們應(yīng)稱為架構(gòu)設(shè)計(jì)模式,而非廣義上的編碼設(shè)計(jì)模式澎嚣。
架構(gòu)設(shè)計(jì)模式之MVC和MVVM
寫在最后
沒有最后 <( ̄︶ ̄)>