問題:
在物件導向系統的分析與設計過程中經常會遇到,對於某一個商務邏輯(演算法實現)在不同的對象中有不同的細節實現,但是邏輯(演算法)的架構(或通用的應用演算法)是相同的。這時候我們一般需要把邏輯(演算法)架構放在抽象基類中,並定義好細節的介面,採用繼承的方式在子類中實現細節。
定義:
模板方法模式是類的行為模,定義一個操作中的演算法骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可以重定義演算法的某些特定步驟。
意圖:
Template是採用繼承的方式實現演算法的異構,將通用演算法封裝在抽象基類中,並將不同的演算法細節放到子類中實現,使得子類可以置換掉父類的可變部分,但是子類卻不可以改變模板方法所代表的頂級邏輯。
使用了物件導向設計中的DIP(依賴倒置:Dependency Inversion Principles)原則。實現父類調用子類的操作,子類(低層模組)實現父類(高層模組)聲明的介面。這樣控制權在父類(高層模組),低層模組反而要依賴高層模組。實現反向控制結構效果。
參與者:
•AbstractClass(抽象模版)角色:
定義了一個或多個抽象的作基本方法(Primitive Method),以便讓子類實現。它們是一個模版方法(Template Method)的組成的具體邏輯步驟。
定義並實現了一個模版方法。這個模版方法一般是一個具體方法,它給出一個邏輯骨架,而邏輯的組成步驟在相應的抽象基本方法(Primitive Method)中,延遲到子類實現。
•ConcreteClass(具體模版)角色:
實現父類所定義的一個或多個抽象方法。
每一個抽象模版角色都可以有任意多個具體模版角色與之對應,而每一個具體模版角色都可以給出這些抽象方法的不同實現,從而將演算法細節讓子類實現(多態)。
UML:
執行個體說明:
諾基亞手機工廠
對於手機生產,N8,N9有一定的生產差異,比如CPU,記憶體有不同的安裝方式,但是,實現生產步驟都是一樣的。
uml圖如下:
代碼:
/// <summary>
/// 手機生產 抽象模板
/// </summary>
public abstract class AbstractCreatePhone
{
/// <summary>
/// 安裝主板(抽象行為)
/// </summary>
public abstract void BuildMb();
public abstract void BuildCpu();
public abstract void SetSystem();
/// <summary>
/// 模板方法 給出邏輯架構
/// </summary>
public void CreatePhone()
{
BuildMb();
BuildCpu();
SetSystem();
System.Console.WriteLine("手機生產完成!");
}
}
/// <summary>
/// N8手機生產具體類
/// </summary>
public class ConcreteCreateN8 : AbstractCreatePhone
{
public ConcreteCreateN8()
{
System.Console.WriteLine("開始生產N8!");
}
public override void BuildMb()
{
System.Console.WriteLine("N8主板安裝完成!");
}
public override void BuildCpu()
{
System.Console.WriteLine("N8 CPU 安裝完成!");
}
public override void SetSystem()
{
System.Console.WriteLine("N8 系統 安裝完成!");
}
}
/// <summary>
/// N8手機生產具體類
/// </summary>
public class ConcreteCreateN9 : AbstractCreatePhone
{
public ConcreteCreateN9()
{
System.Console.WriteLine("開始生產N9!");
}
public override void BuildMb()
{
System.Console.WriteLine("N9主板安裝完成!");
}
public override void BuildCpu()
{
System.Console.WriteLine("N9 CPU 安裝完成!");
}
public override void SetSystem()
{
System.Console.WriteLine("N9 系統 安裝完成!");
}
}
/// <summary>
/// 用戶端測試代碼
/// </summary>
public void TemplateMethodTest()
{
//執行個體化生產類
AbstractCreatePhone acp = new ConcreteCreateN8();
//生產手機
acp.CreatePhone();
}
優點:
•模板方法模式通過把不變的行為放在基類,去除了子類中的重複代碼、保證了邏輯的統一性。
•子類實現演算法的某些細節,有助於演算法的擴充(多態)。
•父類的模板方法控制子類的具體使用,使得我們不用過於關心父類的全部商務程序。
缺點:
•演算法的骨架有改變的話,需要改變抽象類別,違背了“開閉原則”。
應用情景:
•一次性實現一個演算法的不變的部分,並將可變的行為留給子類來實現。
•要完成在某一具有相同步驟的演算法,但個別步驟在不同情境中有不同實現時。