设计模式之模板模式
模板模式的原文定义是定义一个操作中的算法框架,将某些特定步骤延迟到子类中实现,使子类可重写或重新定义算法框架中的某些特定步骤而不会改变算法框架结构。下面是其UML简图
上图中TemplateMethod就是抽象模板类提供的算法框架调用,PrimitOperation方法就是指的某些可延迟到子类实现的特定步骤,也就是模板类提供的可自定义实现的接口方法。这就好比我们去银行办理业务,整体业务流程大致可能是取号、填写需办理业务资料、等待、办理,但是我们会发现该业务流程中填写需办理业务资料时不同业务需要填写资料可能不同并且有些业务可能不需要填写资料,这就是我们业务处理流程中的变化点,而办理如何业务的流程顺序框架可以看成是固定不变的业务处理模板,框架模板是提前制定好的,而流程中的变化点则是在具体处理不同业务时才选择实现的。所以实现模板模式中的抽象模板类往往可以提供基本方法、模板方法和钩子方法这三种类型的方法。
基本方法就是子类可重写实现并在模板方法中调用的接口方法,对应上面UML图中的PrimitOperation方法。
模板方法就是模板类定义的固有算法框架实现,其中就会按固有流程去调度基本方法,对应上面UML图中的TemplateMethod方法,模板方法可以有多个,但不允许子类重写(确保算法框架不被改变),所以C++中模板方法若为虚函数一般会加上final修饰。
钩子方法就是为了在固有算法流程框架的基础上更好的适应外界条件变化而定义的用于模板方法对基本方法调用的判断条件设置的方法。
下面我们就根据银行业务办理流程来模拟设计一个简单的模板用于银行业务办理,UML简图:
完整测试代码:
include <iostream>
using namespace std;
class BankBusiness //银行业务处理基类
{
public:
void businessProcess(); //业务处理固定流程框架,即固有业务流程模板方法
protected:
virtual void fillInformation() = 0; //需要子类重写的填写资料信息的基本方法
virtual bool needFillInfo() = 0; //用于判断是否需要填写资料流程
private:
//以下为固有流程框架需要的固定流程算法
void takeNumber();
void waitCall();
void handelBusiness();
};
void BankBusiness::takeNumber()
{
cout << "取号" << endl;
}
void BankBusiness::waitCall()
{
cout << "等待叫号" << endl;
}
void BankBusiness::handelBusiness()
{
cout << "业务办理" << endl;
}
void BankBusiness::businessProcess()
{
takeNumber();
if(needFillInfo()) {
fillInformation();
}
waitCall();
handelBusiness();
}
//开户业务
class OpenAccount : public BankBusiness
{
public:
virtual void fillInformation();
virtual bool needFillInfo();
};
void OpenAccount::fillInformation()
{
cout << "填写个人开户信息" << endl;
}
bool OpenAccount::needFillInfo()
{
return true;
}
//存取款业务
class DepositWithdrawMoney : public BankBusiness
{
public:
virtual bool needFillInfo();
virtual void fillInformation() {}; //存取款业务无需填写资料,所以定义为空函数
};
bool DepositWithdrawMoney::needFillInfo()
{
return false;
}
int main()
{
cout << ">>>>>>>>>>>开户业务办理<<<<<<<<<<<<" << endl;
BankBusiness *openAccount = new OpenAccount;
openAccount->businessProcess();
cout << ">>>>>>>>>>>存取款业务办理<<<<<<<<<<<<" << endl;
BankBusiness *deposit = new DepositWithdrawMoney;
deposit->businessProcess();
return 0;
}
程序运行结果:
在有变化的与不变的方法混合在一起,不变的方法总会不停重复出现时,通过模板模式,我们可以将这些不变的方法统一放置到一边,就可以摆脱这些重复不变方法的纠缠,这样提取了不变部分的公共操作封装在父类中,在减小了维护成本,方便维护的同时将变化的部分交给子类去实现又可以很好的扩展变化的部分从而保持良好的扩展性;适合多个类有公共方法并且处理逻辑大致相同的情况;公共重复的核心方法就设计为模板方法,其他的细节功能设计为基本方法,方便扩展应对变化。
模板模式与策略模式的区别就在于其主要思想;模板模式的主要思想是定义一个算法流程,将一些特定步骤的具体实现、延迟到子类。使得可以在不改变算法流程的情况下,通过不同的子类、来实现“定制”流程中的特定的步骤。策略模式的主要思想则是使不同的算法可以被相互替换,而不影响客户端的使用。