C++设计模式01-——模板设计模式
一、使用动机
在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?
二、应用场景
一个库开发人员,你根据开发者经常性、重复性的需求,编写了一个库,为开发者提供稳定的模块:
class Library {
public:
void Step1() {
//...
}
void Step3() {
//...
}
void Step5() {
//...
}
};
一段时间的使用后,通过观察发现用户经常会使用这样地使用此库:
class Application {
public:
bool Step2() {
//...
return true;//为了使编译通过所赋值
}
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();
return 0;
}
于是,库开发人员想要将此流程定下来,包装成一个函数方法,使得用户更加轻松地完成开发,但是,问题出现了,尽管步骤大体相同,但是每个用户定义的Step2()和Step4()函数内容都不相同,无法固定具体的内容…
三、问题解决
经过思考,想到面向对象,想到虚函数和继承,没错!只要把这些步骤做成模板,其中用户自定义的部分使用纯虚函数强迫用户重写自定义方法,即可达到目的。
库模板:
class 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() { //稳定
//.....
}
virtual bool Step2() = 0;//变化
virtual void Step4() = 0; //变化
};
int main()
{
Library* pLib = new Application();
pLib->Run();
delete pLib;
return 0;
}
用户使用:
class Application : public Library {
protected:
virtual bool Step2() {
//... 子类重写实现
return true;
}
virtual void Step4() {
//... 子类重写实现
}
};
一个细节: 这两个函数写成纯虚函数后,必须在子类中重写才可以实例化子类对象,才可以使用Run函数。
四、代码附录
测试代码:
-
未优化初始代码
#include <iostream> using namespace std; class Library { public: void Step1() { //... } void Step3() { //... } void Step5() { //... } }; class Application { public: bool Step2() { //... return true; } 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(); return 0; }
-
优化之后:
class 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() { //稳定 //..... } virtual bool Step2() = 0;//变化 virtual void Step4() = 0; //变化 }; class Application : public Library { protected: virtual bool Step2() { //... 子类重写实现 return true; } virtual void Step4() { //... 子类重写实现 } }; int main() { Library* pLib = new Application(); pLib->Run(); delete pLib; return 0; }
五、代码对比
library库
用户自定义方法
方法调用
六、经验总结
-
Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
-
除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你” 的反向控制结构是Template Method的典型应用。
-
在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法
THE END…