模板方法模式
先看一下通用的類圖:
其中 TemplateMethod 就是模板方法,operation1 和 operation2 就是基本方法,模板方法是通過彙總或排序基本方法而產生的結果集。
這樣看可能會很枯燥,來個具體的例子先。
某公司生產不同的車子,見下面的類圖:
有四個基本的方法還有一個模板方法。模本方法在抽象類中做實現。當然這個模板方法也稱爲具體方法,因爲其在抽象類中進行了實現。其他四個基本方法是在子類中進行實現的,稱之爲抽象方法。等下再講解一下鉤子方法。
兩種車子分別繼承HummerModel模型。但是客戶其實更關心的是其中的run()方法,只要run()方法可行,基本就OK了,那麼我們沒必要暴露這麼多方法出來了。修改一下類圖如下:
就四個基本方法設置成 protected 模式。run 方法既然子類都不修改,
可以設置成 final 類型。這就是模板方法模式了。
突然,客戶又有了新的需求,用戶要控制車子的喇叭的響停,這就相當於子類車要來控制車的模型了,這就引出了鉤子方法。即使得子類可以控制父類的行爲。類圖修改如下:
run()方法可以修改爲
final public void run() {
//先發動汽車
this.start();
//引擎開始轟鳴
this.engineBoom();
//喇嘛想讓它響就響,不想讓它響就不響
if(this.isAlarm()){
this.alarm();
}
//到達目的地就停車
this.stop();
}
//鉤子方法,默認喇叭是會響的
protected boolean isAlarm(){
return true;
}
}
在實現類中增加的方法:
@Override
protected boolean isAlarm() {
return this.alarmFlag;
}
//要不要響喇叭,是有客戶的來決定的
public void setAlarm(boolean isAlarm){
this.alarmFlag = isAlarm;
}
這樣就可以讓調用者來設置setAlarm方法的參數來進行控制車子是否發出聲響了。調用如下:
HummerH1Model h1 = new HummerH1Model();
h1.setAlarm(true);
h1.run(); //汽車跑起來了;
這就達到了子類方法控制父類的行爲了。
總結:
模板方法模式是基於繼承的代碼複用技術,它體現了面向對象的諸多重要思想,是一種使用較爲頻繁的模式。模板方法模式廣泛應用於框架設計中,以確保通過父類來控制處理流程的邏輯順序(如框架的初始化,測試流程的設置等)。
****1 、模式優點****
模板方法模式的主要優點如下:
(1) 在父類中形式化地定義一個算法,而由它的子類來實現細節的處理,在子類實現詳細的處理算法時並不會改變算法中步驟的執行次序。
(2) 模板方法模式是一種代碼複用技術,它在類庫設計中尤爲重要,它提取了類庫中的公共行爲,將公共行爲放在父類中,而通過其子類來實現不同的行爲,它鼓勵我們恰當使用繼承來實現代碼複用。
(3) 可實現一種反向控制結構,通過子類覆蓋父類的鉤子方法來決定某一特定步驟是否需要執行。
(4) 在模板方法模式中可以通過子類來覆蓋父類的基本方法,不同的子類可以提供基本方法的不同實現,更換和增加新的子類很方便,符合單一職責原則和開閉原則。
**2 、模式缺點**
模板方法模式的主要缺點如下:
需要爲每一個基本方法的不同實現提供一個子類,如果父類中可變的基本方法太多,將會導致類的個數增加,系統更加龐大,設計也更加抽象,此時,可結合橋接模式來進行設計。
**3 、模式適用場景**
在以下情況下可以考慮使用模板方法模式:
(1) 對一些複雜的算法進行分割,將其算法中固定不變的部分設計爲模板方法和父類具體方法,而一些可以改變的細節由其子類來實現。即:一次性實現一個算法的不變部分,並將可變的行爲留給子類來實現。
(2) 各子類中公共的行爲應被提取出來並集中到一個公共父類中以避免代碼重複。
(3) 需要通過子類來決定父類算法中某個步驟是否執行,實現子類對父類的反向控制。