(Boolan)C++设计模式 <二> ——模版方法
定一个操作中的算法的骨架(稳定的),而将一些步骤延迟(容易变化的)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重新定义(Override覆写)该算法的某写特定步骤
——《设计模式(GoF)》
关于模版方法的设计模式,我们先来看这样一个伪码描述。下面的伪码主要是有两个开发人员来构成的代码,分别是库开发人员和应用程序的开发人员。
对于库的开发人员来说,已经开发完成了所需要功能的1、3、5三个步骤;而如果要实现这个完整功能,需要应用程序的开发人员实现其中的2和4这两步。同时,还需要应用程序的开发者,在使用的时候,依次来调用库和自己开发的这几个函数。
//程序库开发人员
class Library{
public:
void Step1(){
//...
}
void Step3(){
//...
}
void Step5(){
//...
}
};
//应用程序开发人员
class Application{
public:
bool Step2(){
//...
}
void Step4(){
//...
}
};
int main()
{
Library lib();
Application app();
lib.Step1();
if (app.Step2()){
lib.Step3();
}
for (int i = 0; i < 4; i++){
app.Step4();
}
lib.Step5();
}
对于以上的伪码描述来说,是否存在一些问题呢?
首先,对应用程序的开发人员来说,他需要自己开发其中的第二和第五步的函数的开发。对于应用程序的开发者来说,要求是比较高的,必须对库中的函数情况比较了解,重写的两个函数的难度也相对较大,对于函数整体执行流程也不被库函数的开发人员所控制。
第二,也是最关键的问题,库开发人员和应用程序的开发人员所开发的内容的耦合度很高,彼此相互交织在一起,还需要由用开发人员来组织整体调用流程。未来程序的扩展性和可维护性的难度都比较大。
那么针对以上的问题,是否有办法来解决呢?
//程序库开发人员
class Library{
public:
//稳定 template method
void Run(){
Step1();
if (Step2()) { //支持变化 ==> 虚函数的多态调用
Step3();
}
for (int i = 0; i < 4; i++){
Step4(); //支持变化 ==> 虚函数的多态调用
}
Step5();
}
virtual ~Library(){ }
protected:
void Step1() { //稳定
//.....
}
void Step3() {//稳定
//.....
}
void Step5() { //稳定
//.....
}
virtual bool Step2() = 0;//变化
virtual void Step4() =0; //变化
};
//应用程序开发人员
class Application : public Library {
protected:
virtual bool Step2(){
//... 子类重写实现
}
virtual void Step4() {
//... 子类重写实现
}
};
int main()
{
Library* pLib=new Application();
lib->Run();
delete pLib;
}
}
对于这段伪码描述来说,库的开发人员,对于他的开发库,进行了一定的重构。首先,能够开发库的开发人员能增加了两个虚函数。然后,库的开发人员定义了一个run方法,在run方法中,按照步骤调用了按照规则来调用的几个方法。那么这个时候,对于应用程序的开发人员来说,此时只需要重写库函数中定义的函数,避免了应用程序开发人员犯错的概率,并且,对于应用程序来说使用库的流程变得极其简单,只需要调用run方法即可,而不需要考虑具体的调用流程和规则。
对于 这段代码来说,耦合性相对也很低,库的开发人员完全不需要管应用开发人员的开发情况,可以独立完成自己的开发任务。对于应用程序的开发人员来说,只需要用简单的应用即可,而不需要考虑其中具体的实现过程。所以这样的设计方法的耦合性较低。
对于Template Method来说,有一个前提,就是Run()方法必须要是稳定的。如果Run()不稳定,那么没有一个稳定的软件的骨架,就不存在这样一种设计模式。假定,所有方式都是稳定,那么其实也没有必要使用设计模式。
Template Method的UML要点总结:
Template Method是一种非常基础性的设计模式,在面向对象的系统中,有着大量的应用。他用最简洁的机制(虚函数的多态性)为很多应用程序的框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
除了可以灵活对应子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用。
在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),一般推荐将他们设置为protected方法。