概念
模板指一些可以套用的公共內容,例如網頁模板是當網站中有許多頁面版式色彩相同的情況下,將其定義為網頁模板,並定義其中部分可編輯,部分不可編輯,那麼在利用網頁模板製作其他頁面時就會很方便,不易出錯。
在設計模式中,模板方法模式中模板和生活中模板概念非常類似,在一個抽象類中定義一個操作中的演算法骨架(對應於模板),而將一些步驟延遲到子類中去實現(對應根據自己的情況向模板填充內容)。
在物件導向程式設計過程中,程式設計師常常會遇到這種情況:設計一個系統時知道了演算法所需的關鍵步驟,而且確定了這些步驟的執行順序,但某些步驟的具體實現還未知,或者說某些步驟的實現與具體的環境相關。此時就可以採用模板方法進行設計。
例如公司的入職流程,進入公司,入職準備、入職報到、辦理入職手續、進行入職培訓,轉正,入職結束進入崗位。這些步驟都很固定,但是不同的公司,流程中每個步驟稍有不同。這些不同的可以在具體實現上進行填充。
特點
優點:
它封裝了不變部分,擴充套件可變部分。它把認為是不變部分的演算法封裝到父類中實現,而把可變部分演算法由子類繼承實現,便於子類繼續擴充套件。
它在父類中提取了公共的部分程式碼,實現了程式碼複用。
部分方法是由子類實現的,因此子類可以通過擴充套件方式增加相應的功能,符合開閉原則。
缺點:
對每個不同的實現都需要定義一個子類,這會導致類的個數增加,系統更加龐大,設計也更加抽象。
父類中的抽象方法由子類實現,子類執行的結果會影響父類的結果,這導致一種反向的控制結構,它提高了程式碼閱讀的難度。
因為引入了一個抽象類,如果具體實現過多的話,需要使用者或開發人員需要花更多的時間去理清類之間的關係。
模式結構
根據模板方法模式類圖結構,有利於我們理清該模式中類之間的關係,具體類圖如下:
模板方法模式中涉及的角色:
抽象模板角色:定義了一個或多個抽象操作,以便讓子類實現,這些抽象操作稱為基本操作。它由一個模板方法和若干個基本方法構成。
模板方法:定義了演算法的骨架,按某種順序呼叫其包含的基本方法。
基本方法:是整個演算法中的一個步驟,包含了抽象方法、具體方法。
具體模板角色:實現父類所定義的一個或多個抽象方法。
應用場景
演算法的整體步驟很固定,但其中個別部分易變時,這時候可以使用模板方法模式,將容易變的部分抽象出來,供子類實現。
當多個子類存在公共的行為時,可以將其提取出來並集中到一個公共父類中以避免程式碼重複。首先,要識別現有程式碼中的不同之處,並且將不同之處分離為新的操作。最後,用一個呼叫這些新的操作的模板方法來替換這些不同的程式碼。
實現
以入職流程為例,進行具體的實現。
using System; namespace 模板模式 { class EntryProcess { static void Main(string[] args) { SamsungEntryProcess samsung = new SamsungEntryProcess(); HuaweiEntryProcess huawei = new HuaweiEntryProcess(); samsung.JoiningCompany(); huawei.JoiningCompany(); Console.Read(); } } // 抽象類,入職流程 public abstract class TemplateEntryProcess { // 模板方法,不要把模版方法定義為 Virtual 或 abstract 方法,避免被子類重寫,防止更改流程的執行順序 public void JoiningCompany() { this.entryCompany(); // 進入公司 this.preparationForEntry(); // 入職前準備,整理衣帽等 this.registrationForEmployment(); // 入職報到 this.entryProcedures(); // 辦理入職手續 this.inductionTraining(); // 入職培訓 this.evaluationOfConversion(); // 轉正評估 this.entryOver(); // 入職結束,進入崗位 } public abstract void entryCompany(); public void preparationForEntry() { Console.WriteLine("做準備,整理衣帽等;"); } public void registrationForEmployment() { Console.WriteLine("入職報到;"); } public void entryProcedures() { Console.WriteLine("辦理入職手續;"); } public void inductionTraining() { Console.WriteLine("進行入職培訓;"); } public void evaluationOfConversion() { Console.WriteLine("完成入職前培訓,進行轉正評估;"); } public void entryOver() { Console.WriteLine("入職流程完成,進入崗位。"); } } // 具體子類,三星入職 public class SamsungEntryProcess: TemplateEntryProcess { public override void entryCompany() { Console.WriteLine("進入三星公司"); } } // 具體子類,華為入職 public class HuaweiEntryProcess: TemplateEntryProcess { public override void entryCompany() { Console.WriteLine("進入華為公司"); } } }
執行後結果
進入三星公司
做準備,整理衣帽等;
入職報到;
辦理入職手續;
進行入職培訓;
完成入職前培訓,進行轉正評估;
入職流程完成,進入崗位。
進入華為公司
做準備,整理衣帽等;
入職報到;
辦理入職手續;
進行入職培訓;
完成入職前培訓,進行轉正評估;
入職流程完成,進入崗位。