Template Method 模板模式
组件协作模式通过晚绑定,来实现框架与应用程序之间的松耦合。是框架和引用程序协作常用的。
动机
有完整的,稳定的整体操作,但子步骤却有很多变化的需求,或者无法和整体结构同时实现(有早晚关系)
定义
定义一个操作中的算法骨架(稳定点),而将一些步骤延迟(变化点)到子类中,Template method 使子类可以不改变一个算法的结构即可重定义(override 重写)该算法的某些步骤。
示例代码

这里给出的 demo 的图示如上,假设这里算法的实现主题有 5 个接口,其中红色的 1,3,5 都是库开发人员已经写好了的接口,2,4 则是由应用开发人员来完成。这里就有如下两种实现方式:
// 第一种模式:算法流程由应用开发人员来写
// 库开发人员完成的工作
class Library {
public:
void Step1() {
// ...
}
void Step3() {
// ...
}
void Step5() {
// ...
}
};
// 应用开发人员完成的工作
class Application {
public:
void 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();
}
这里 Library 一般写的比较早,而 Application 写的比较晚,结构化软件中,晚写的调用早写的,就叫做早绑定。
另一种模式则为,库开发人员完成部分接口,并且写好算法的主流程,2,4 步声明为虚函数,这时流程固定,应用开发人员只要实现 2, 4 两个虚函数,这种将实现通过继承延迟到子类的方式,早写的调用晚写的接口,就是晚绑定:
// 第二种情况:算法框架由库开发人员来写
// 库开发人员完成的工作
class Library {
public:
~Library(){}
// Template Method: 流程稳定
void Run() {
Step1();
if (Step2()) { // 支持变化 => 虚函数的多态调用
Step3();
}
for(int i = 0; i<4; ++i) {
Step4(); // 支持变化 => 虚函数的多态调用
}
Step5();
}
protected:
void Step1() { // 稳定
// ...
}
void Step3() { // 稳定
// ...
}
void Step5() { // 稳定
// ...
}
virtual void Step2() = 0;
virtual void Step4() = 0;
};
// 应用开发人员完成的工作
class Application : public Library {
protected:
void Step2() override {
// ...
}
void Step4() override {
// ...
}
};
int main() {
Library* lib = new Application();
lib->Run();
delete lib;
}
以上这种形式将稳定的内容固定,利用虚函数的多态性为很多程序框架提供灵活的扩展点的方式就是 Template Method 模板模式。
结构图

总结
- Template Method 模式虚函数的多态性为很多程序框架提供灵活的扩展点。
- 晚调用,不要调用我,让我来调用你。
- 一般推荐放在 protected 里,因为 public 让别人单独调用一般没有意义,一般放在流程中,以上主要是变化和稳定的关系。
其他设计模式汇总:
[设计模式] —— 设计模式的介绍及分类