準備一個抽象類,將部分邏輯以具體方法以及具體構造子的形式實現,然后聲明一些抽象方法來迫使子類實現剩余的邏輯。不同的子類可以以不同的方式實現這些抽象方法,從而對剩余的邏輯有不同的實現。這就是模版方法模式的用意。
很多人可能沒有想到,模版方法模式實際上是所有模式中最為常見的幾個模式之一,而且很多人可能使用過模版方法模式而沒有意識到自己已經使用了這個模式。模版方法模式是基于繼承的代碼復用的基本技術,模版方法模式的結構和用法也是面向對象設計的核心。
模版方法模式需要開發抽象類和具體子類的設計師之間的協作。一個設計師負責給出一個算法的輪廓和骨架,另一些設計師則負責給出這個算法的各個邏輯步驟。代表這些具體邏輯步驟的方法稱做基本方法(primitive method);而將這些基本法方法總匯起來的方法叫做模版方法(template method),這個設計模式的名字就是從此而來。
模版方法模式中的方法
模版方法中的方法可以分為兩大類:模版方法(Template Method)和基本方法(Primitive Method)。
模版方法
一個模版方法是定義在抽象類中的,把基本操作方法組合在一起形成一個總算法或一個總行為的方法。這個模版方法一般會在抽象類中定義,并由子類不加以修改地完全繼承下來。
基本方法
基本方法又可以分為三種:抽象方法(Abstract Method)、具體方法(Concrete Method)和鉤子方法(Hook Method)。
- 抽象方法:一個抽象方法由抽象類聲明,由具體子類實現。在C#語言里一個抽象方法以abstract關鍵字標示出來。
- 具體方法:一個具體方法由抽象類聲明并實現,而子類并不實現或置換。在C#語言里面,一個具體方法沒有abstract關鍵字。
- 鉤子方法:一個鉤子方法由抽象類聲明并實現,而子類會加以擴展。通常抽象類給出的實現是一個空實現,作為方法的默認實現。(Visual FoxPro中項目向導建立的項目會使用一個AppHook類實現監視項目成員變化,調整系統結構的工作。)鉤子方法的名字通常以do開始。
模板方法模式的實現
完整代碼示例(code):模板方法模式的實現很簡單,這里為了方便初學者的學習和參考,將給出完整的實現代碼(所有代碼采用 C++實現,并在 VC 6.0 下測試運行)。
代碼片斷 1:Template.h
//Template.h#ifndef _TEMPLATE_H_#define _TEMPLATE_H_class AbstractClass{ public: virtual ~AbstractClass(); void TemplateMethod(); protected: virtual void PrimitiveOperation1() = 0; virtual void PrimitiveOperation2() = 0; AbstractClass(); private:};class ConcreteClass1:public AbstractClass{ public: ConcreteClass1(); ~ConcreteClass1(); protected: void PrimitiveOperation1(); void PrimitiveOperation2(); private:};class ConcreteClass2:public AbstractClass{ public: ConcreteClass2(); ~ConcreteClass2(); protected: void PrimitiveOperation1(); void PrimitiveOperation2(); private:};#endif //~_TEMPLATE_H_
代碼片斷 2:Template.cpp
#include "Template.h"#include <iostream>using namespace std;AbstractClass::AbstractClass(){}AbstractClass::~AbstractClass(){}void AbstractClass::TemplateMethod(){ this->PrimitiveOperation1(); this->PrimitiveOperation2();}ConcreteClass1::ConcreteClass1(){}ConcreteClass1::~ConcreteClass1(){}void ConcreteClass1::PrimitiveOperation1(){ cout<<"ConcreteClass1...PrimitiveOperat ion1"<<endl;}void ConcreteClass1::PrimitiveOperation2(){ cout<<"ConcreteClass1...PrimitiveOperat ion2"<<endl;}ConcreteClass2::ConcreteClass2(){}ConcreteClass2::~ConcreteClass2(){}void ConcreteClass2::PrimitiveOperation1(){cout<<"ConcreteClass2...PrimitiveOperation1"<<endl;}void ConcreteClass2::PrimitiveOperation2(){ cout<<"ConcreteClass2...PrimitiveOperat ion2"<<endl;}
代碼片斷 3:main.cpp
#include "Template.h"#include <iostream>using namespace std;int main(int argc,char* argv[]){ AbstractClass* p1 = new ConcreteClass1(); AbstractClass* p2 = new ConcreteClass2(); p1->TemplateMethod(); p2->TemplateMethod(); return 0;}
代碼說明:由于模板方法模式的實現代碼很簡單,因此解釋是多余的。其關鍵是將通用算法(邏輯)封裝起來,而將算法細節讓子類實現(多態)。
唯一注意的是我們將原語操作(細節算法)定義未保護(Protected)成員,只供模板方法調用(子類可以)。
適用場景
一次性實現一個算法的不變的部分,并將可變的行為留給子類來實現。
各子類中公共的行為應被提取出來并集中到一個公共父類中以避免代碼重復。這是O p d y k e 和J o h n s o n 所描述過的“重分解以一般化”的一個很好的例子[ O J 9 3 ]。首先識別現有代碼中的不同之處,并且將不同之處分離為新的操作。最后,用一個調用這些新的操作的模板方法來替換這些不同的代碼。
控制子類擴展。模板方法只在特定點調用“h o o k ”操作(參見效果一節),這樣就只允許在這些點進行擴展。