模板方法模式 java
1. 模板方法模式概述
在現實生活中,很多事情都包含幾個實現步驟,例如請客吃飯,無論吃什麼,一般都包含點單、吃東西、買單等幾個步驟,通常情況下這幾個步驟的次序是:點單 –> 吃東西 –> 買單。在這三個步驟中,點單和買單大同小異,最大的區別在於第二步——吃什麼?吃麵條和吃滿漢全席可大不相同,如圖1所示:
圖1 請客吃飯示意圖
在軟體開發中,有時也會遇到類似的情況,某個方法的實現需要多個步驟(類似“請客”),其中有些步驟是固定的(類似“點單”和“買單”),而有些步驟並不固定,存在可變性(類似“吃東西”)。為了提高程式碼的複用性和系統的靈活性,可以使用一種稱之為模板方法模式的設計模式來對這類情況進行設計,在模板方法模式中,將實現功能的每一個步驟所對應的方法稱為基本方法(例如“點單”、“吃東西”和“買單”),而呼叫這些基本方法同時定義基本方法的執行次序的方法稱為模板方法(例如“請客”)。在模板方法模式中,可以將相同的程式碼放在父類中,例如將模板方法“請客”以及基本方法“點單”和“買單”的實現放在父類中,而對於基本方法“吃東西”,在父類中只做一個宣告,將其具體實現放在不同的子類中,在一個子類中提供“吃麵條”的實現,而另一個子類提供“吃滿漢全席”的實現。通過使用模板方法模式,一方面提高了程式碼的複用性,另一方面還可以利用面向物件的多型性,在執行時選擇一種具體子類,實現完整的“請客”方法,提高系統的靈活性和可擴充套件性。
模板方法模式定義如下:
模板方法模式:定義一個操作中演算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。 Template Method Pattern: Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure. |
模板方法模式是一種基於繼承的程式碼複用技術,它是一種類行為型模式。
模板方法模式是結構最簡單的行為型設計模式,在其結構中只存在父類與子類之間的繼承關係。通過使用模板方法模式,可以將一些複雜流程的實現步驟封裝在一系列基本方法中,在抽象父類中提供一個稱之為模板方法的方法來定義這些基本方法的執行次序,而通過其子類來覆蓋某些步驟,從而使得相同的演算法框架可以有不同的執行結果。模板方法模式提供了一個模板方法來定義演算法框架,而某些具體步驟的實現可以在其子類中完成。
2. 模板方法模式結構與實現
2.1 模式結構
模板方法模式結構比較簡單,其核心是抽象類和其中的模板方法的設計,其結構如圖2
圖2 模板方法模式結構圖
由圖2可知,模板方法模式包含如下兩個角色:
(1) AbstractClass(抽象類):在抽象類中定義了一系列基本操作(PrimitiveOperations),這些基本操作可以是具體的,也可以是抽象的,每一個基本操作對應演算法的一個步驟,在其子類中可以重定義或實現這些步驟。同時,在抽象類中實現了一個模板方法(Template Method),用於定義一個演算法的框架,模板方法不僅可以呼叫在抽象類中實現的基本方法,也可以呼叫在抽象類的子類中實現的基本方法,還可以呼叫其他物件中的方法。
(2) ConcreteClass(具體子類):它是抽象類的子類,用於實現在父類中宣告的抽象基本操作以完成子類特定演算法的步驟,也可以覆蓋在父類中已經實現的具體基本操作。
2.2 模式實現
在實現模板方法模式時,開發抽象類的軟體設計師和開發具體子類的軟體設計師之間可以進行協作。一個設計師負責給出一個演算法的輪廓和框架,另一些設計師則負責給出這個演算法的各個邏輯步驟。實現這些具體邏輯步驟的方法即為基本方法,而將這些基本方法彙總起來的方法即為模板方法,模板方法模式的名字也因此而來。下面將詳細介紹模板方法和基本方法:
1. 模板方法
一個模板方法是定義在抽象類中的、把基本操作方法組合在一起形成一個總演算法或一個總行為的方法。這個模板方法定義在抽象類中,並由子類不加以修改地完全繼承下來。模板方法是一個具體方法,它給出了一個頂層邏輯框架,而邏輯的組成步驟在抽象類中可以是具體方法,也可以是抽象方法。由於模板方法是具體方法,因此模板方法模式中的抽象層只能是抽象類,而不是介面。
2. 基本方法
基本方法是實現演算法各個步驟的方法,是模板方法的組成部分。基本方法又可以分為三種:抽象方法(Abstract Method)、具體方法(Concrete Method)和鉤子方法(Hook Method)。
(1) 抽象方法:一個抽象方法由抽象類宣告、由其具體子類實現。在C#語言裡一個抽象方法以abstract關鍵字標識。
(2) 具體方法:一個具體方法由一個抽象類或具體類宣告並實現,其子類可以進行覆蓋也可以直接繼承。
(3) 鉤子方法:一個鉤子方法由一個抽象類或具體類宣告並實現,而其子類可能會加以擴充套件。通常在父類中給出的實現是一個空實現(可使用virtual關鍵字將其定義為虛擬函式),並以該空實現作為方法的預設實現,當然鉤子方法也可以提供一個非空的預設實現。
在模板方法模式中,鉤子方法有兩類:第一類鉤子方法可以與一些具體步驟“掛鉤”,以實現在不同條件下執行模板方法中的不同步驟,這類鉤子方法的返回型別通常是bool型別的,這類方法名一般為IsXXX(),用於對某個條件進行判斷,如果條件滿足則執行某一步驟,否則將不執行,如下程式碼片段所示:
[csharp] view plain copy print?- ……
- //模板方法
- publicvoid TemplateMethod()
- {
- Open();
- Display();
- //通過鉤子方法來確定某步驟是否執行
- if (IsPrint())
- {
- Print();
- }
- }
- //鉤子方法
- publicbool IsPrint()
- {
- returntrue;
- }
- ……
……
//模板方法
public void TemplateMethod()
{
Open();
Display();
//通過鉤子方法來確定某步驟是否執行
if (IsPrint())
{
Print();
}
}
//鉤子方法
public bool IsPrint()
{
return true;
}
……
在程式碼中IsPrint()方法即是鉤子方法,它可以決定Print()方法是否執行,一般情況下,鉤子方法的返回值為true,如果不希望某方法執行,可以在其子類中覆蓋鉤子方法,將其返回值改為false即可,這種型別的鉤子方法可以控制方法的執行,對一個演算法進行約束。
還有一類鉤子方法就是實現體為空的具體方法,子類可以根據需要覆蓋或者繼承這些鉤子方法,與抽象方法相比,這類鉤子方法的好處在於子類如果沒有覆蓋父類中定義的鉤子方法,編譯可以正常通過,但是如果沒有覆蓋父類中宣告的抽象方法,編譯將報錯。
在模板方法模式中,抽象類的典型程式碼如下:
[csharp] view plain copy print?- abstractclass AbstractClass
- {
- //模板方法
- publicvoid TemplateMethod()
- {
- PrimitiveOperation1();
- PrimitiveOperation2();
- PrimitiveOperation3();
- }
- //基本方法—具體方法
- publicvoid PrimitiveOperation1()
- {
- //實現程式碼
- }
- //基本方法—抽象方法
- publicabstractvoid PrimitiveOperation2();
- //基本方法—鉤子方法
- publicvirtualvoid PrimitiveOperation3()
- { }
- }
abstract class AbstractClass
{
//模板方法
public void TemplateMethod()
{
PrimitiveOperation1();
PrimitiveOperation2();
PrimitiveOperation3();
}
//基本方法—具體方法
public void PrimitiveOperation1()
{
//實現程式碼
}
//基本方法—抽象方法
public abstract void PrimitiveOperation2();
//基本方法—鉤子方法
public virtual void PrimitiveOperation3()
{ }
}
在抽象類中,模板方法TemplateMethod()定義了演算法的框架,在模板方法中呼叫基本方法以實現完整的演算法,每一個基本方法如PrimitiveOperation1()、PrimitiveOperation2()等均實現了演算法的一部分,對於所有子類都相同的基本方法可在父類提供具體實現,例如PrimitiveOperation1(),否則在父類宣告為抽象方法或鉤子方法,由不同的子類提供不同的實現,例如PrimitiveOperation2()和PrimitiveOperation3()。
可在抽象類的子類中提供抽象步驟的實現,也可覆蓋父類中已經實現的具體方法,具體子類的典型程式碼如下:
[csharp] view plain copy print?- class ConcreteClass : AbstractClass
- {
- publicoverridevoid PrimitiveOperation2()
- {
- //實現程式碼
- }
- publicoverridevoid PrimitiveOperation3()
- {
- //實現程式碼
- }
- }
class ConcreteClass : AbstractClass
{
public override void PrimitiveOperation2()
{
//實現程式碼
}
public override void PrimitiveOperation3()
{
//實現程式碼
}
}
在模板方法模式中,由於面向物件的多型性,子類物件在執行時將覆蓋父類物件,子類中定義的方法也將覆蓋父類中定義的方法,因此程式在執行時,具體子類的基本方法將覆蓋父類中定義的基本方法,子類的鉤子方法也將覆蓋父類的鉤子方法,從而可以通過在子類中實現的鉤子方法對父類方法的執行進行約束,實現子類對父類行為的反向控制。