一、模板模式
1、模板模式
1)定义
定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override重写)该算法的某些特定步骤。
2)动机(motivation)
> 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。
> 如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?
结构化软件设计流程:
面向对象软件设计流程:
3)类图
AbstractClass是抽象类,也是一个抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体方法。
ConCreteClass,实现父类所定义的一个或多个抽象方法。每个AbstractClass都可以有任意多个ConCreteClass与之对应,而每一个ConCreteClass都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。
4)代码实现
#include <iostream>
#include <string>
#include<memory>
using namespace std;
class Library
{
public:
void run() //template method
{
step1();
while (!step2()) //多态调用
step3();
step4(); //多态调用
step5();
}
virtual ~Library() {}
protected:
void step1()
{
cout << "Library.step1()" << endl;
}
void step3()
{
cout << "Library.step3()" << endl;
}
void step5()
{
cout << "Library.step5()" << endl;
}
protected:
int number{ 0 };
private: //NVI: Non-Virtual Interface
virtual bool step2() = 0;
virtual int step4() = 0;
};
class App : public Library
{
private:
bool step2() override
{
//Library::step2();//静态绑定
cout << "App.step2()" << endl;
number++;
return number >= 3;
}
int step4() override
{
cout << "App.step4() : " << number << endl;
return number;
}
};
int main()
{
std::unique_ptr<Library> library = std::make_unique<App>();
//1. 存储成本:虚表指针 + 虚表结构(共享)
//2. 调用成本: 间接指针辨析, 无法inline
library->run();
system("pause");
return 0;
}
5)要点总结
> Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
> 除了可以灵活对应子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用。
> 在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将他们设置为protected或private方法(公有接口非虚NVI,Non-Virtual Interface)。
二、CRTP习语
1、CRTP
1)定义
CRTP(Curious Recurring Template Pattern):奇异递归模板模式。通过将基类模板参数设置为子类,从而实现静态多态(静态接口),或者扩展接口(委托实现)。
2)要点
> class Sub:public Base<Sub>通过模板参数,将子类类型在编译时注入基类,从而实现在基类中提前获取子类类型信息。
> static_cast<T*>(this)将基类指针转型为模板子类T的指针。
> Base类型为不完整类型,不能使用Sub参与内存布局,但可以在函数内使用(发生调用,模板编译时辨析即可)。
> 删除对象,也要使用编译时多态进行删除,避免直接delete。
3)代码实现
#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <vector>
using namespace std;
template <typename T>
class Library
{
public:
void run() //template method
{
step1();
while (!sub()->step2()) //子类调用
step3();
sub()->step4(); //子类调用
step5();
}
void destroy()
{
delete sub();
}
protected:
T* sub() {
return static_cast<T*>(this);
}
void step1()
{
cout << "Library.step1()" << endl;
}
void step3()
{
cout << "Library.step3()" << endl;
}
void step5()
{
cout << "Library.step5()" << endl;
}
protected:
int number{ 0 };
bool step2() { return false; }
int step4() { return 0; }
public:
~Library() {
cout << "Library dtor" << endl;
}
};
class App : public Library<App>
{
public:
bool step2()
{
cout << "App.step2()" << endl;
number++;
return number >= 3;
}
int step4()
{
cout << "App.step4() : " << number << endl;
return number;
}
~App() {
cout << "App dtor" << endl;
}
};
template<typename T>
void invoke(Library<T> &lib)
{
lib.run();
}
int main()
{
{
Library<App> *pLib = new App();
pLib->run();
pLib->destroy();
cout << endl;
}
cout << "----------------------------" << endl;
{
auto lambda = [](auto p) { p->destroy(); };
unique_ptr<Library<App>, decltype(lambda)> uptr(new App(), lambda);
uptr->run();
}
system("pause");
return 0;
}