模板方法模式

应对问题

在项目构建过程中, 对于某一些问题, 都是有着稳定的整体操作结构, 但是在各个子步骤中却有着许多的改变需求, 并且由于某些原因不能将子任务和整体结构同时实现

比如对于一个应用程序具有 5 个步骤

HR0VNn.png

作为 Library 开发人员, 设计了整个应用程序的架构和整体步骤, 但是对于 2, 4 步骤, 并不能知道作为程序开发者将如何实现这些步骤, 所以可以使用 模板方法模式 来保证流程的稳定

模式定义

定义一个操作中的算法的骨架 (稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的某些特定步骤 ——《设计模式》GoF

结构 (Structure)

HRc8s0.png

代码实现

对于整个算法(程序的某个任务)的具体骨架是稳定的, 但是对于其中某些步骤并不稳定的话, 可以设计一个抽象类, 将稳定的部分以及整体流程设计出来, 并将不稳定的, 变化的部分交给程序发开者通过继承的方式进行扩展

Library

Library 开发者提供一个抽象类 来提供整个程序的流程骨架以及部分稳定的步骤过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
lass 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() {
//.....
}

/**
* Library 事先并不知道应用者要如何实现这些步骤,
* 所以将这两个步骤以纯虚函数的方式定义, 待应用开发者进行实现
*/
virtual bool Step2() = 0;
virtual void Step4() =0;
};

application 开发者

1
2
3
4
5
6
7
8
9
10
11
//继承 Library 并提供自己对于步骤 2 4 的实现
class Application : public Library {
protected:
virtual bool Step2(){
//...
}

virtual void Step4() {
//...
}
};

主程序中使用

1
2
3
4
5
6
7
int main()
{
Library* pLib=new Application();
lib->Run();
delete pLib;
}
}

要点总结

  • Template Method 模式是一种非常基础的设计模式, 在面向对象系统中有着大量的应用. 它使用最简洁的机制 (虚函数的多态性) 为很多应用程序框架提供了灵活的扩展点, 是代码复用方面的基本实现结构

  • 除了可以灵活应对子步骤的变化外, “不要调用我, 让我来调用你” 的反向控制结构是 Template Method 的典型应用.

  • 在具体实现方面, 被 Template Method 调用的虚方法可以具有实现, 也可以没有任何实现 (抽象方法, 纯虚方法), 但一般推荐将它们设置为 protected 方法