动机

在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很做变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。

定义

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

结构

image-20221228133650108

未使用模板方法的示例:

结构化软件设计流程

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
// 某开发人员开发的lib库
class lib
{
public:
void step1(){};

void step3(){};

void step5(){};
}

// 某开发人员开发的应用
class app
{
public:
bool step2(){};

void step4(){};
}

// 主程序
int main()
{
// 程序主流程
lib mylib;
app myapp;
mylib.step1();

if(myapp.step2())
{
mylib.step3();
}

for(int i=0; i<2;i++)
{
myapp.step4();
}
mylib.step5();
}

使用模板方法

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
45
46
47
48
49
50
51
52

// 某开发人员开发的lib库
class lib
{
public:

void run(){ // 程序主流程

step1();

if(step2()) // 支持变化 ==> 虚函数的多态调用
{
step3();
}

for(int i=0; i<2;i++)
{
step4(); // 支持变化 ==> 虚函数的多态调用
}
step5();
};

void step1(){};

void step3(){};

void step5(){};

virtual bool step2() = 0;

virtual void step4() = 0;

virtual ~lib(){}; // 不加的话,子类无法析构

}

// 某开发人员开发的应用
class app :public lib
{
public:
bool step2(){}; // 重写要执行的操作

void step4(){}; // 重写要执行的操作
}

// 主程序
int main()
{
lib* mylib = new app();
mylib.run();
}

总结:

Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用。
在具体实现方面,被Template Method调用的虚方法可以有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般它们设置为protected方法。