设计模式-模板方法模式(Template Method)

在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑(算法实现)在不同的对象中有不同的细节实现,但是逻辑(算法)的框架(或通用的应用算法)是相同的。Template 提供了这种情况的一个实现框架。

问题提出

现在假设有一种算法,算法过程分为5个阶段,其中第1 3 5三个阶段由程序库开发人员设计完成,第2 5两个阶段需要由应用程序开发人员根据不同的业务需求进行填充,从而完成完整的算法流程。

解法1.0

程序库开发人员要完成算法的1 3 5三个步骤并提供一个算法的总体框架模板,应用程序开发人员需要实现算法的第2 4两个步骤,并根据程序库开发人员给的模板实现整体的算法。具体代码如下:

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
// 程序库开发人员 
class Library
{
public:
void Step1() {
// ...Step1
}
void Step3() {
// ...Step3
}
void Step5() {
// ...Step5
}
};

// 应用程序开发人员
class Application
{
public:
bool Step2() {
return 1 < 2 ? true : false;
}
void Step4() {
// Step4
}
};

// 应用程序开发人员
int main()
{
Library *lib = new Library;
Application *app = new Application;
lib->Step1();
if (app->Step2())
lib->Step3();
for (int i = 0; i < 5; ++i)
app->Step4();
lib->Step5();
delete lib;
delete app;
return 0;
}

这种实现方式的缺点是,应用程序开发人员需要了解算法的整体流程,并在每次需要使用算法时都需要额外维护一份代码。如果有使用原生 Windows API 开发窗口程序的经历,编译器自动生成的 WinMain 函数就是这样的实现方式。

解法2.0

程序库开发人员实现了整个算法的外部接口Run()方法,实现了其中的第1 3 5三个步骤,将2 4两个步骤写成纯虚函数,留给应用程序开发人员实现。应用程序开发人员继承 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
45
46
47
48
// 程序库开发人员 
class Library
{
public:
void Run() {
Step1();
if (Step2())
Step3();
for (int i = 0; i < 5; ++i)
Step4();
Step5();
}
virtual ~Library() {

}
protected:
void Step1() {
// ...Step1
}
void Step3() {
// ...Step3
}
void Step5() {
// ...Step5
}
virtual bool Step2() = 0;
virtual void Step4() = 0;
};

// 应用程序开发人员
class Application : public Library
{
public:
bool Step2() {
return 1 < 2 ? true : false;
}
void Step4() {
// ...Step4
}
};

// 应用程序开发人员
int main()
{
Library* p = new Application;
p->Run();
return 0;
}

总结

下面给出 模板方法模式(Template Method)的类图。

TemplatePattern