设计模式二十三:template method(模板方法)——类行为模式
template method(模板方法)——类行为模式
1.意图
定义一个操作中的算法骨架,而将一些步骤延迟到子类中,template method使得子类可以不改变一个算法的结构即可重新定义算法的某些特定步骤。
2.动机
通过使用抽象操作定义一个算法中的一些步骤,模板方法确定了他们的先后顺序,但是他允许子类改变具体步骤以满足各自的需求。
3.适用性
1)一次实现一个算法的不变部分,把可变部分的行为留给子类实现
2)各子类中公共的行为应该被提取出来并集中到一个公共的父类中以避免代码重复
3)控制子类扩展。模板方法只有在特定点调用hook操作,这样允许子类在这些点上加以扩展。
4.结构
参考:http://www.cnblogs.com/tjcjxy/archive/2010/11/28/1890263.html
5.参与者
abstractClass抽象类
定义抽象的原语操作,具体的子类将重定义他们以实现一个算法的各个步骤。
实现一个模板方法,定义一个算法的骨架,该模板方法不仅调用原语操作,也调用定义在abstractClass或者其他对象中的操作。
concreteClass具体类
实现原语操作以完成算法中的特定子类相关的步骤。
6.协作
concreteClass靠AbstractClass来实现算法中不变的步骤
7.效果
模板方法是一种代码复用的基本技术
模板方法导致一种反响的控制结构,“好莱坞法则”:“别来找我们,我们找你”。这指一个父类调用子类的操作,而不是相反。
模板方法调用下列类型的操作:
1)具体的操作(concreteClass或者对客户类的操作)
2)具体的abstractClass操作(通常对子类有用的操作)
3)原语操作
4)factory method
5)钩子操作:提供了缺省的行为,子类可以在必要时进行扩展,一般缺省操作都是空操作
8.实现
1)使用c++访问控制
原语操作可以定义为protected成员,保证只被模板调用。必须重定义的原语操作必须定义为纯虚函数。模板方法自身不需要被重新定义,可以将模板方法定义为非虚成员函数。
2)尽量减少原语操作
3)命名约定
给重定义的操作名字前加上一个前缀以识别
9.代码示例
#include<iostream> using namespace std; class vehicle { public: void start() { cout<<"let's start..."<<endl; } virtual void addBody(){} virtual void addWheel(){} virtual void addOilTank(){} virtual void trialRun(){} }; class car:public vehicle { public: void addBody() { cout<<"we got a body of a car"<<endl; } void addWheel() { for(int i=0;i<4;i++) { cout<<"add a wheel to the body"<<endl; } } void addOilTank() { cout<<"add a small oil tank to the body"<<endl; } void trialRun() { cout<<"let the car run 10 min"<<endl; } }; class truck:public vehicle { public: void addBody() { cout<<"we got a body of a truck"<<endl; } void addWheel() { for(int i=0;i<8;i++) { cout<<"add a wheel to the body"<<endl; } } void addOilTank() { cout<<"add a huge oil tank to the body"<<endl; } void trialRun() { cout<<"let the car run 200 min"<<endl; } }; class assemble { public: assemble(vehicle *_v) { v = _v; } void startAssemble() { v->start(); v->addBody(); v->addWheel(); v->addOilTank(); v->trialRun(); } private: vehicle *v; }; int main() { vehicle *c = new car(); assemble *ass = new assemble(c); ass->startAssemble(); cout<<endl<<"another"<<endl<<endl; vehicle *ca = new truck(); assemble *a = new assemble(ca); a->startAssemble(); }
10.相关模式
factoryMethod
常被模板方法调用
strategy
模板方法是用继承来改变算法的一部分。strategy是用委托来改变整个算法。