意图:
定义一个操作中的算法的骨架(稳定),而将一些步骤延迟到子类中(变化)。template method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
template method并不是狭义上的模板函数(尽管语法层面,也能实现同样的效果),而是一次性实现算法稳定不变的部分,并将可变的行为留给子类来实现,也就是实现了“晚绑定”。
既然有“晚绑定”,对应的就有“早绑定”。
假设有一个库文件:
class Library {
public:
void step1(){
}
void step3(){
}
void step5(){
}
}
应用开发:
class App{
public:
void step2();
void step4();
}
int main ()
{
Library lib();
App app();
// 实现一个算法
lib.step1();
app.step2();
lib.step3();
app.step4();
lib.step5();
return 0;
}
上述做法中,库开发人员写了1,3,5方法,应用开发人员写了2,4还有程序主流程。程序主流程调用了库文件中的内容,也就是所谓的“早绑定”。
再看另一种写法:
库文件:
class Library{
public:
void run(){
step1();
if(step2()){ // 子类实现
step3();
}
while(something()){
step4(); //子类实现
}
step5();
}
virtual ~Library(){}
protected:
step1();
step3();
step5();
virtual bool step2() = 0;
virtual void step4() = 0;
}
应用开发:
class App:public Library{
public:
bool step2(){
//...
}
void step4(){
//...
}
}
int main()
{
Library* lib = new App();
lib->run();
delete lib;
return 0;
}
这里的做法是库文件通过虚函数机制去调用后续子类实现的2,4方法,也就是所谓的“晚绑定”。template method会导致这种反向的控制结构。库文件会去找应用实现方法,也称为“好莱坞法则”:即“别来找我,我们找你”。这些有个小tips:方法是protected的,单个方法并无意义,作为run函数的部分整体对外开放才有意义。
学习到这里,有几句设计模式的总结值得写一下:
1、设计的要点是“寻找变化点”,然后在变化点上运用设计模式;
2、设计模式不应先入为主,一上来就使用设计模式是一种误用(一般情况下,大牛忽略),没有一步到位的设计模式,随着版本迭代,不断更新完善。
以上内容主要参考李建忠的设计模式教程。
网友评论