在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑(算法实现)在不同的对象中有不同的细节实现,但是逻辑(算法)的框架(或通用的应用算法)是相同的。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() { } void Step3() { } void Step5() { } };
class Application { public: bool Step2() { return 1 < 2 ? true : false; } void 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() { } void Step3() { } void Step5() { } virtual bool Step2() = 0; virtual void Step4() = 0; };
class Application : public Library { public: bool Step2() { return 1 < 2 ? true : false; } void Step4() { } };
int main() { Library* p = new Application; p->Run(); return 0; }
|
总结
下面给出 模板方法模式(Template Method)的类图。
