iOS 設計模式之二十三(模板方法模式)

一、概念

1、模板方法模式的動機

? 在現實生活中,很多事情都包含幾個相對固定的步驟,比如去公司工作,你需要先打開電腦,然后用電腦工作,最后關閉電腦回家。在軟件開發中,也有類似的情況,某個方法的實現需要多個步驟(類似“工作”),其中有些步驟是固定的(類似“電腦開機”),而有些步驟并不固定(類似“具體工作”)。

? 為了提高代碼的復用性和系統的靈活性,可以使用一種稱之為模板方法模式的設計模式來對這類情況進行設計,在模板方法模式中,將實現功能的每一個步驟所對應的方法稱為基本方法(比如“開機”、“具體工作”、“關機”等),而調用這些基本方法同時定義基本方法的執行次序的方法稱為模板方法(比如“在公司上班”)。

2、模板方法模式的定義

? 模板方法模式(Template Method Pattern):定義一個操作中算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。

? 模板方法模式是一種基于繼承的代碼復用技術,它是一種類行為型模式

3、模板方法模式的2個角色

1)AbstractClass(抽象類):在抽象類中定義了一系列基本操作(PrimitiveOperations),這些基本操作可以是具體的,也可以是抽象的,每一個基本操作對應算法的一個步驟,在其子類中可以重定義或實現這些步驟。同時,在抽象類中實現了一個模板方法(Template Method),用于定義一個算法的框架,模板方法不僅可以調用在抽象類中實現的基本方法,也可以調用在抽象類的子類中實現的基本方法,還可以調用其他對象中的方法。
2)ConcreteClass(具體子類):它是抽象類的子類,用于實現在父類中聲明的抽象基本操作以完成子類特定算法的步驟,也可以覆蓋在父類中已經實現的具體基本操作。

4、模板方法與基本方法的概念

模板方法

? 一個模板方法是定義在抽象類中的、把基本操作方法組合在一起形成一個總算法或一個總行為的方法。這個模板方法定義在抽象類中,并由子類不加以修改地完全繼承下來。模板方法是一個具體方法,它給出了一個頂層邏輯框架,而邏輯的組成步驟在抽象類中可以是具體方法,也可以是抽象方法。由于模板方法是具體方法,因此模板方法模式中的抽象層只能是抽象類,而不是接口。

基本方法

基本方法是實現算法各個步驟的方法,是模板方法的組成部分。基本方法又可以分為三種:

1)抽象方法(Abstract Method):一個抽象方法由抽象類聲明、由其具體子類實現。在C#和Java語言里一個抽象方法以abstract關鍵字標識。

2)具體方法(Concrete Method):一個具體方法由一個抽象類或具體類聲明并實現,其子類可以進行覆蓋也可以直接繼承。

3)鉤子方法(Hook Method):一個鉤子方法由一個抽象類或具體類聲明并實現,而其子類可能會加以擴展。鉤子方法分兩類:第一類鉤子方法可以與一些具體步驟“掛鉤”,以實現在不同條件下執行模板方法中的不同步驟,這類鉤子方法的返回類型通常是bool類型的,這類方法名一般為IsXXX();第二類鉤子方法就是實現體為空的具體方法,這類鉤子方法的好處在于子類如果沒有覆蓋父類中定義的鉤子方法,編譯可以正常通過。

5、結構圖
模板方法模式

二、示例

? 在模板方法模式中,由于面向對象的多態性,子類對象在運行時將覆蓋父類對象,子類中定義的方法也將覆蓋父類中定義的方法。因此程序在運行時,子類的鉤子方法也將覆蓋父類的鉤子方法,從而可以通過在子類中實現的鉤子方法對父類方法的執行進行約束,實現子類對父類行為的反向控制。

? 本Demo以程序員工作為例:

1)先創建一個Coder類,類中有模板方法和一系列基本方法,表示抽象類;

2)然后創建Employee類和Leader類,都繼承自Coder類,表示具體子類。

具體代碼如下:

Coder類:

// 程序猿:抽象類
@interface Coder : NSObject
- (void)work; //模板方法
- (void)startComputer; //具體方法
- (void)coding; //抽象方法,OC沒有abstract這個關鍵字,這里選擇不實現方法
- (void)closeComputer; //具體方法
- (BOOL)isNeedCloseComputer; //鉤子方法
@end

@implementation Coder
- (void)work {
    [self startComputer];
    [self coding];
    if ([self isNeedCloseComputer]) {
        [self closeComputer];
    }
}

- (void)startComputer {
    NSLog(@"電腦開機");
}

- (void)closeComputer {
    NSLog(@"電腦關機");
}

- (BOOL)isNeedCloseComputer {
    NSLog(@"Windows電腦需要關機");
    return YES;
}
@end

Employee類和Leader類:

// Employee 普通員工類
@interface Employee : Coder
@end
@implementation Employee
- (void)coding { // 實現抽象方法
    NSLog(@"程序猿努力敲代碼");
}
@end

// Leader 領導類
@interface Leader : Coder
@end
@implementation Leader
- (void)coding { // 實現抽象方法
    NSLog(@"領導指揮大家敲代碼");
}

- (BOOL)isNeedCloseComputer { // 重寫鉤子方法
    NSLog(@"MacBook Pro不需要關機");
    return NO;
}
@end

運行代碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Employee *employee = [Employee new];
    [employee work];
    NSLog(@"---------------------");
    
    Leader *leader = [Leader new];
    [leader work];
}

打印結果:

電腦開機
程序猿努力敲代碼
Windows電腦需要關機
電腦關機
---------------------
電腦開機
領導指揮大家敲代碼
MacBook Pro不需要關機

三、總結

? 模板方法模式是基于繼承的代碼復用技術,廣泛應用于框架設計中,以確保通過父類來控制處理流程的邏輯順序(如框架的初始化,測試流程的設置等)。

1、優點

1、在父類中形式化地定義一個算法,而由它的子類來實現細節的處理,在子類實現詳細的處理算法時并不會改變算法中步驟的執行次序。

2、模板方法模式是一種代碼復用技術,它在類庫設計中尤為重要,它提取了類庫中的公共行為,將公共行為放在父類中,而通過其子類來實現不同的行為,它鼓勵我們恰當使用繼承來實現代碼復用。

3、可實現一種反向控制結構,通過子類覆蓋父類的鉤子方法來決定某一特定步驟是否需要執行。

4、在模板方法模式中可以通過子類來覆蓋父類的基本方法,不同的子類可以提供基本方法的不同實現,更換和增加新的子類很方便,符合單一職責原則和開閉原則。

2、缺點

? 需要為每一個基本方法的不同實現提供一個子類,如果父類中可變的基本方法太多,將會導致類的個數增加,系統更加龐大,設計也更加抽象,此時,可結合橋接模式來進行設計。

3、適用場景

1、對一些復雜的算法進行分割,將其算法中固定不變的部分設計為模板方法和父類具體方法,而一些可以改變的細節由其子類來實現。即:一次性實現一個算法的不變部分,并將可變的行為留給子類來實現。

2、各子類中公共的行為應被提取出來并集中到一個公共父類中以避免代碼重復。

3、需要通過子類來決定父類算法中某個步驟是否執行,實現子類對父類的反向控制。

4、iOS應用舉例

? 在Cocoa Touch框架中,最常見的UIViewController,如果需要適配屏幕旋轉,那么必須重寫各種旋轉的方法,比如shouldAutorotate就是典型的鉤子方法。還有UIView有個drawRect方法,如果需要執行定制繪圖,那么子類可以重寫這個方法來達到效果,drawRect也是鉤子方法。

Demo地址:iOS-Design-Patterns

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容