概述:
我們最近在開發一個支援多種壓縮類型檔案的解壓縮且製作成pdf的一個應用。對我們的架構來說我們需要支援多種壓縮檔類型,但卻有固定的操作順序(先解壓縮,在讀取裡面的檔案分析、製作pdf)。我們抽取他們的共同點:這些操作的固定順序,把他放到我們的父類裡;他們的變化點:這些個具體的操作,去留給不同的子類去實現。這個就是模板方法模式,他定義一個操作中的演算法的骨架(例子中的固定的操作順序),而將一些步驟延遲到子類中(例子中的多種壓縮檔的解壓縮)。
Template Method使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。是一種比較簡單的設計模式,但卻是代碼複用的一項基本技術,在類庫中尤其重要。使用的也比較普遍。
類圖與執行個體:
這裡涉及到兩個角色:
抽象模版(AbstractClass
)角色:
定義了一個或多個抽象操作,以便讓子類實現。這些抽象操作叫做基本操作,它們是一個頂級邏輯的組成步驟。
定義並實現了一個模版方法。這個模版方法一般是一個具體方法,它給出了一個頂級邏輯的骨架,而邏輯的組成步驟在相應的抽象操作中,延遲到子類實現。頂級邏輯也有可能調用一些具體方法。這個就是定義了我們的固定的操作順序。
具體模版(ConcreteClass
)角色:
實現父類所定義的一個或多個抽象方法,它們是一個頂級邏輯的組成步驟。
每一個抽象模版角色都可以有任意多個具體模版角色與之對應,而每一個具體模版角色都可以給出這些抽象方法(也就是頂級邏輯的組成步驟)的不同實現,從而使得頂級邏輯的實現各不相同。就是對我們的多個壓縮檔的不同的解壓縮的支援。
執行個體:
#include <iostream>template <typename T> class CaffeineBeverage //咖啡因飲料{public:void PrepareRecipe() //咖啡因飲料沖泡法{BoilWater(); //把水煮沸Brew(); //沖泡PourInCup(); //把咖啡因飲料倒進杯子AddCondiments(); //加調料}void BoilWater(){std::cout << "把水煮沸" << std::endl;}void Brew(){static_cast<T *>(this)->Brew();}void PourInCup(){std::cout << "把咖啡倒進杯子" << std::endl;}void AddCondiments(){static_cast<T *>(this)->AddCondiments();}};class Coffee : public CaffeineBeverage<Coffee>{public:void Brew(){std::cout << "用沸水沖泡咖啡" << std::endl;}void AddCondiments(){std::cout << "加糖和牛奶" << std::endl;}};class Tea : public CaffeineBeverage<Tea>{public:void Brew(){std::cout << "用沸水浸泡茶葉" << std::endl;}void AddCondiments(){std::cout << "加檸檬" << std::endl;}};int main(void){std::cout << "沖杯咖啡:" << std::endl;Coffee c;c.PrepareRecipe();std::cout << std::endl;std::cout << "沖杯茶:" << std::endl;Tea t;t.PrepareRecipe();return 0;}
適用性:
1.一次性實現一個演算法的不變的部分,並將可變的行為留給子類來實現。
2.各子類中公用的行為應被提取出來並集中到一個公用父類中以避免代碼重複。這是Opdyke和Johnson所描述過的“重分解以一般化”的一個很好的例子。首先識別現有代碼中的不同之處,並且將不同之處分離為新的操作。最後,用一個調用這些新的操作的模板方法來替換這些不同的代碼。
3.控制子類擴充。模板方法只在特定點調用“Hook”操作,這樣就只允許在這些點進行擴充。
實現要點:
1.Template Method模式是一種非常基礎性的設計模式,在物件導向系統中有著大量的應用。它用最簡潔的機制(虛函數的多態性)為很多應用程式架構提供了靈活的擴充點,是代碼複用方面的基本實現結構。
2.除了可以靈活應對子步驟的變化外,“不用調用我,讓我來調用你”的反向控制結構是Template Method的典型應用。
3.在具體實現方面,被Template Method調用的虛方法可以具有實現,也可以沒有任何實現(抽象方法,純虛方法),但一般推薦將它們設定為protected方法。
LCL_data原創於CSDN.NET【http://blog.csdn.net/lcl_data/article/details/9199961】
其他設計模式文章請參考:我所理解的設計模式