模板模式(Template Method)
模板模式(Template Method)
1.模式動機
在面向物件程式設計過程中,程式設計師常常會遇到這種情況:設計一個系統時知道了演算法所需的關鍵步驟,而且確定了這些步驟的執行順序,但某些步驟的具體實現還未知,或者說某些步驟的實現與具體的環境相關。
例如,去銀行辦理業務一般要經過以下4個流程:取號、排隊、辦理具體業務、對銀行工作人員進行評分等,其中取號、排隊和對銀行工作人員進行評分的業務對每個客戶是一樣的,可以在父類中實現,但是辦理具體業務卻因人而異,它可能是存款、取款或者轉賬等,可以延遲到子類中實現。
這樣的例子在生活中還有很多,例如,一個人每天會起床、吃飯、做事、睡覺等,其中“做事”的內容每天可能不同。我們把這些規定了流程或格式的例項定義成模板,允許使用者根據自己的需求去更新它,例如,簡歷模板、論文模板、Word 中模板檔案等。
2.模式定義
模板方法(Template Method)模式的定義如下:定義一個操作中的演算法骨架,而將演算法的一些步驟延遲到子類中,使得子類可以不改變該演算法結構的情況下重定義該演算法的某些特定步驟。它是一種類行為型模式。
3.模式結構
模板方法模式包含以下主要角色。
- 抽象類/抽象模板(Abstract Class)
抽象模板類,負責給出一個演算法的輪廓和骨架。它由一個模板方法和若干個基本方法構成。這些方法的定義如下。
① 模板方法:定義了演算法的骨架,按某種順序呼叫其包含的基本方法。
② 基本方法:是整個演算法中的一個步驟,包含以下幾種型別。
- 抽象方法:在抽象類中宣告,由具體子類實現。
- 具體方法:在抽象類中已經實現,在具體子類中可以繼承或重寫它。
- 鉤子方法:在抽象類中已經實現,包括用於判斷的邏輯方法和需要子類重寫的空方法兩種。
- 具體子類/具體實現(Concrete Class)
具體實現類,實現抽象類中所定義的抽象方法和鉤子方法,它們是一個頂級邏輯的一個組成步驟。
4.程式碼分析
//抽象類 abstract class AbstractClass { //模板方法 public void TemplateMethod() { SpecificMethod(); abstractMethod1(); abstractMethod2(); } //具體方法 public void SpecificMethod() { System.out.println("抽象類中的具體方法被呼叫..."); } //抽象方法1 public abstract void abstractMethod1(); //抽象方法2 public abstract void abstractMethod2(); } //具體子類 class ConcreteClass extends AbstractClass { public void abstractMethod1() { System.out.println("抽象方法1的實現被呼叫..."); } public void abstractMethod2() { System.out.println("抽象方法2的實現被呼叫..."); } } public class TemplateMethodPattern { public static void main(String[] args) { AbstractClass tm = new ConcreteClass(); tm.TemplateMethod(); } }
5.模式分析
模板方法模式需要注意抽象類與具體子類之間的協作。它用到了虛擬函式的多型性技術以及“不用呼叫我,讓我來呼叫你”的反向控制技術。現在來介紹它們的基本結構。
6.例項
出國留學手續一般經過以下流程:索取學校資料,提出入學申請,辦理因私出國護照、出境卡和公證,申請簽證,體檢、訂機票、準備行裝,抵達目標學校等,其中有些業務對各個學校是一樣的,但有些業務因學校不同而不同,所以比較適合用模板方法模式來實現。
7.優缺點
優點:
- 它封裝了不變部分,擴充套件可變部分。它把認為是不變部分的演算法封裝到父類中實現,而把可變部分演算法由子類繼承實現,便於子類繼續擴充套件。
- 它在父類中提取了公共的部分程式碼,便於程式碼複用。
- 部分方法是由子類實現的,因此子類可以通過擴充套件方式增加相應的功能,符合開閉原則。
缺點:
- 對每個不同的實現都需要定義一個子類,這會導致類的個數增加,系統更加龐大,設計也更加抽象,間接地增加了系統實現的複雜度。
- 父類中的抽象方法由子類實現,子類執行的結果會影響父類的結果,這導致一種反向的控制結構,它提高了程式碼閱讀的難度。
- 由於繼承關係自身的缺點,如果父類新增新的抽象方法,則所有子類都要改一遍。
適用環境:
- 演算法的整體步驟很固定,但其中個別部分易變時,這時候可以使用模板方法模式,將容易變的部分抽象出來,供子類實現。
- 當多個子類存在公共的行為時,可以將其提取出來並集中到一個公共父類中以避免程式碼重複。首先,要識別現有程式碼中的不同之處,並且將不同之處分離為新的操作。最後,用一個呼叫這些新的操作的模板方法來替換這些不同的程式碼。
- 當需要控制子類的擴充套件時,模板方法只在特定點呼叫鉤子操作,這樣就只允許在這些點進行擴充套件。
8.模式擴充套件
在模板方法模式中,基本方法包含:抽象方法、具體方法和鉤子方法,正確使用“鉤子方法”可以使得子類控制父類的行為。如下面例子中,可以通過在具體子類中重寫鉤子方法 HookMethod1() 和 HookMethod2() 來改變抽象父類中的執行結果。