模板方法屬於行為型設計模式,行為型設計模式主要關注對象之間職責分配和算法的問題。類行為型模式使用繼承來分配類之間的職責,模板方法就是個類行為型模式。對象行為型模式使用組合來分配職責。在我們構建軟件的過程中大部分時候我們都是在思考實體之間的職責,怎樣的職責分配最合理,不至於過重,又不至於過輕,而且又不越權。
一、什么是模板方法模式
模板方法模式在一個方法中定義一個算法的骨架,而將一些步驟的實現延遲到子類中。模板方法使得子類可以在不改變算法結構的情況下,重新定義算法中某些步驟的具體實現。
看到“設計模式”這四個字我們往往會覺得高深莫測,但是模板方法模式卻是一個例外,你要關注的就是一個方法而已。
模板方法模式確實非常簡單,僅僅使用繼承機制,但是它是一個應用非常廣泛的模式。
二、模板方法模式的使用場景
當系統中算法的骨架是固定的時候,而算法的實現可能有很多種的時候,就需要使用模板方法模式。
- 多個子類有共有的方法,並且邏輯基本相同
- 重要、復雜的算法,可以把核心算法設計為模板方法,周邊的相關細節功能則由各個子類實現
- 重構時,模板方法是一個經常使用的方法,把相同的代碼抽取到父類中,然后通過構造函數約束其行為。
舉例:需要做一個報表打印程序,用戶規定需要表頭,正文,表尾。但是客戶的需求會變化,一會希望這樣顯示表頭,一會希望那樣顯示。
這時候采用模板方式就合適。
三、模板方法模式的優缺點
優點:
- 封裝不變部分,擴展可變部分。把認為不變部分的算法封裝到父類中實現,而可變部分的則可以通過繼承來繼續擴展。
- 提取公共部分代碼,便於維護。
- 行為由父類控制,子類實現
缺點:
算法骨架需要改變時需要修改抽象類。
按照設計習慣,抽象類負責聲明最抽象、最一般的事物屬性和方法,實現類負責完成具體的事務屬性和方法,但是模板方式正好相反,子類執行的結果影響了父類的結果,會增加代碼閱讀的難度。
四、模板方法模式的實現
AbstractClass類---抽象模板類,定義並實現了一個模板方法。
這個模板一般是一個具體方法,它給出了一個頂級邏輯的骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類實現。
頂級邏輯也有可以調用具體的方法
abstract class AbstractClass { //一些抽象行為放到子類去實現 public abstract void PrivateOperation1(); public abstract void PrivateOperation2(); //模板方法,給出了邏輯的骨架,而邏輯的組成是一些相應的抽象操作,它們都推遲到子類實現 public void TemplateMethod() { PrivateOperation1(); PrivateOperation2(); Console.WriteLine(""); } }
ConcreteClass類,實現父類所定義的一個或者多個抽象方法。
每一個AbstractClass都可以有任意多個ConcreteClass與之對應,而每一個ConcreteClass都可以給出這些抽象方法的不同實現,從而使得頂級邏輯的實現各不相同。
class ConcreteClassA : AbstractClass { public override void PrivateOperation1() { Console.WriteLine("具體類A方法1實現"); } public override void PrivateOperation2() { Console.WriteLine("具體類A方法2實現"); } } class ConcreteClassB : AbstractClass { public override void PrivateOperation1() { Console.WriteLine("具體類B方法1實現"); } public override void PrivateOperation2() { Console.WriteLine("具體類B方法2實現"); } }
客戶端代碼
static void Main(string[] args) { AbstractClass c; c = new ConcreteClassA(); c.TemplateMethod(); c = new ConcreteClassB(); c.TemplateMethod(); Console.Read(); }
五、總結
重復=易錯+難改,模板方法模式是通過父類建立框架,子類在重寫了父類部分方法之后,在調用從父類繼承的方法,產生不同的效果,通過修改子類,影響父類行為的結果,模板方法在一些開源框架中應用非常多,它提供了一個抽象類,然后開源框架寫了一堆子類,如果需要擴展功能,可以繼承此抽象類,然后覆寫protected基本方法,然后在調用一個類似TemplateMethod()的模板方法,完成擴展開發。