模板方法模式(Template Method Pattern)——複雜流程步驟的設計
模式概述
在現實生活中,很多事情都包含幾個實現步驟,例如請客吃飯,無論吃什麼,一般都包含點單、吃東西、買單等幾個步驟,通常情況下這幾個步驟的次序是:點單 --> 吃東西 --> 買單。
在這三個步驟中,點單和買單大同小異,最大的區別在於第二步——吃什麼?不同的人、不同的地方有不同的飲食習慣。如果站在軟體工程的角度來看,這就是變化的地方,也可以說是可擴充套件的點。
軟體開發中,經常會遇到類似的情況,某個方法的實現需要多個步驟(類似“請客”),其中有些步驟是固定的(類似“點單”和“買單”),而有些步驟並不固定,存在可變性(類似“吃東西”)。
為了提高程式碼的複用性和系統的靈活性,可以使用一種稱之為模板方法模式
在模板方法模式中,將實現功能的每一個步驟所對應的方法稱為基本方法
(例如“點單”、“吃東西”和“買單”),而呼叫這些基本方法同時定義基本方法的執行次序的方法稱為模板方法
(例如“請客”)。
在模板方法模式中,可以將相同的程式碼放在父類中,例如將模板方法“請客”以及基本方法“點單”和“買單”的實現放在父類中,而對於基本方法“吃東西”,在父類中只做一個宣告,將其具體實現放在不同的子類中,在一個子類中提供“吃麵條”的實現,而另一個子類提供“吃米飯”的實現。
通過使用模板方法模式,一方面提高了程式碼的複用性,另一方面還可以利用面向物件的多型性,在執行時選擇一種具體子類,實現完整的“請客”方法,提高系統的靈活性和可擴充套件性。
模式定義
模板方法模式定義如下:
模板方法模式(
Template Method Pattern
):定義一個操作中演算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。
模板方法模式是一種基於繼承的程式碼複用技術,它是一種類行為型模式。
模板方法模式是結構最簡單的行為型設計模式,在其結構中只存在父類與子類之間的繼承關係。通過使用模板方法模式,可以將一些複雜流程的實現步驟封裝在一系列基本方法
中,在抽象父類中提供一個稱之為模板方法
的方法來定義這些基本方法的執行次序,而通過其子類來覆蓋某些步驟,從而使得相同的演算法框架可以有不同的執行結果。
模板方法模式提供了一個模板方法來定義演算法框架,而某些具體步驟的實現可以在其子類中完成。
模式結構圖
模板方法模式結構比較簡單,其核心是抽象類和其中的模板方法的設計,其結構如下圖所示:
模板方法模式包含如下兩個角色:
AbstractClass
(抽象類):在抽象類中定義了一系列基本操作(Primitive Operations
),這些基本操作可以是具體的,也可以是抽象的,每一個基本操作對應演算法的一個步驟,在其子類中可以重定義或實現這些步驟。同時,在抽象類中實現了一個模板方法(Template Method
),用於定義一個演算法的框架,模板方法不僅可以呼叫在抽象類中實現的基本方法,也可以呼叫在抽象類的子類中實現的基本方法,還可以呼叫其他物件中的方法。ConcreteClass
(具體子類):它是抽象類的子類,用於實現在父類中宣告的抽象基本操作以完成子類特定演算法的步驟,也可以覆蓋在父類中已經實現的具體基本操作。
模式虛擬碼
抽象父類AbstractClass
負責給出一個演算法的輪廓和框架,如下:
/**
* 抽象模板
*/
public abstract class AbstractClass {
/**
* 具體方法1
*/
public void method1() {
}
/**
* 抽象方法2
*/
public abstract void method2();
/**
* 具體方法3
*/
public void method3() {
}
/**
* 模板方法
*/
public void templateMethod() {
method1();
method2();
method3();
}
}
其中實現這些具體邏輯步驟的方法即為基本方法
,而將這些基本方法彙總起來的方法即為模板方法
。
子類ConcreteClass
負責給出這個演算法的各個邏輯實現,如下:
public class ConcreteClass extends AbstractClass {
@Override
public void method2() {
// 抽象步驟的實現
}
@Override
public void method3() {
// 也可覆蓋父類中已經實現的具體方法
super.method3();
}
}
這樣,就可以通過擴充套件不同的子類來覆蓋某些步驟,從而使得相同的演算法框架可以有不同的執行結果。
模式總結
寫程式碼的一個很重要的思考點就是變與不變
,程式中哪些功能是可變的,哪些功能是不變的,我們可以把不變的部分提取出來,進行公共的實現,把變化的部分分離出來,用介面來封裝隔離變化,或用抽象類約束子類行為。模板方法模式就很好的體現了這一點。
模板方法模式是基於繼承的程式碼複用技術,它體現了面向物件的諸多重要思想,是一種使用較為頻繁的模式。模板方法模式廣泛應用於框架設計中,以確保通過父類來控制處理流程的邏輯順序(如框架的初始化,測試流程的設定等)。
主要優點
- 在父類中形式化地定義一個演算法,而由它的子類來實現細節的處理,在子類實現詳細的處理演算法時並不會改變演算法中步驟的執行次序
- 模板方法模式是一種程式碼複用技術,它提取了公共行為,將公共行為放在父類中,而通過其子類來實現不同的行為,它鼓勵我們恰當使用繼承來實現程式碼複用
- 可實現一種反向控制結構,通過子類覆蓋父類的方法來決定某一特定步驟是否需要執行
- 通過子類來覆蓋父類的基本方法,不同的子類可以提供基本方法的不同實現,更換和增加新的子類很方便,符合單一職責原則和開閉原則
主要缺點
需要為每一個基本方法的不同實現提供一個子類,如果父類中可變的基本方法太多,將會導致類的個數增加,系統更加龐大,設計也更加抽象,此時,可結合 橋接模式 來進行設計。
適用場景
- 對一些複雜的演算法進行分割,將其演算法中固定不變的部分設計為模板方法和父類具體方法,而一些可以改變的細節由其子類來實現
- 各子類中公共的行為應被提取出來並集中到一個公共父類中
- 需要通過子類來決定父類演算法中某個步驟是否執行,實現子類對父類的反向控制
參考書籍:
《設計模式的藝術之道(軟體開發人員內功修煉之道)》—— 劉偉
作者: 位元組飛揚 微信公眾號: 位元組飛揚 出處: https://www.cnblogs.com/bytesfly/ 本文版權歸作者和部落格園共有。歡迎轉載,但必須保留此段宣告,且在文章頁面明顯位置給出原文連線!