这是Bwar在2009年写的设计模式C++实现,代码均可编译可运行,一直存在自己的电脑里,曾经在团队技术分享中分享过,现搬到线上来。
1. 模板方法简述
1.1 目的
定义一个操作中的算法骨架,而将一些步骤延迟到子类中。TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
1.2 适用性
(1) 一次性实现一个算法的不变部分,并将可变的信鸽网i留给子类来实现。
(2) 各子类中公共的行为应被提取出来并几种到一个公共父类中以避免代码重复。
(3) 控制子类的扩展。
2. 模板方法结构图
- AbstractClass:定义抽象的原语操作,具体的子类将重定义它们以实现一个算法的各步骤;实现一个模板方法,定义一个算法的股价。
- ConcreteClass:实现原语操作以完成算法中与特定子类相关的步骤。
3. 模板方法C++实现示例
用模板方法实现游戏的数据统计框架。游戏往往有很多服,称之为大区,MMO游戏中也称之为World。游戏的数据统计会有很多数据指标,所有数据指标都既需要全局的统计,又需要各大区的分开统计,这些数据指标的统计逻辑统计方法又是完全一样的。我们用模板方法定义一个适用于所有指标(活跃、流失、留存、付费等)的统计框架,具体统计逻辑留给子类实现。这样的一个游戏框架在2009年到2013年在行业第一的游戏公司用在一百多款各类型游戏数据统计上,当然,模板方法只是这个游戏数据统计框架最基础的一部分,一个通用的游戏数据统计框架并没有那么简单。
Run()为模板方法,Run()方法内固定依次调用ClusterInit()、Stat()、ClusterStat()。ClusterInit()完成统计初始化,Stat()完成各大区的分区统计,ClusterStat()完成所有大区结果去重统计。整个统计框架实现多线程调度,但具体实现统计逻辑的子类并无须关注线程调度,甚至完全不懂线程的开发人员也能使用该统计框架开发出多线程统计程序。Run()模板方法确保了ClusterInit()只会在第一个进入统计逻辑的线程执行且只执行一次(此时,其他线程处于等待ClusterInit()完成的阻塞状态);Stat()方法在每个线程中同时开始执行;ClusterStat()只在最后一个完成Stat()的线程执行且只执行一次。统计逻辑开发者只需专注于这三个方法的具体实现,其他都交给框架完成,而框架则是通过者三个方法将骨架定义好,确保所有统计都按固定流程走。
代码实现:
AbstractClass.h:
#ifndef ABSTRACTCLASS_H_ #define ABSTRACTCLASS_H_ #include <iostream> using namespace std; class CAbstractClass { public: CAbstractClass(); virtual ~CAbstractClass(); int Run(); protected: virtual int Stat() = 0; virtual int ClusterInit() { return 0; } virtual int ClusterStat() { return 0; } int GetWorldId() { cout << "1" << endl; return 1; } }; #endif /* ABSTRACTCLASS_H_ */
AbstractClass.cpp:
#include "AbstractClass.h" CAbstractClass::CAbstractClass() { // TODO Auto-generated constructor stub cout << "abstract class construct" << endl; } CAbstractClass::~CAbstractClass() { // TODO Auto-generated destructor stub cout << "abstract class destruct" << endl; } int CAbstractClass::Run() { ClusterInit(); Stat(); ClusterStat(); return 0; }
ConcreteClass.h:
#ifndef CONCRETECLASS_H_ #define CONCRETECLASS_H_ #include "AbstractClass.h" class CConcreteClass : public CAbstractClass { public: CConcreteClass(); virtual ~CConcreteClass(); /* virtual int Run() { Stat(); ClusterInit(); ClusterStat(); } */ protected: virtual int Stat(); virtual int ClusterInit() { cout << "CConcreteClass ClusterInit()" << endl; } virtual int ClusterStat() { cout << "CConcreteClass ClusterStat()" << endl; } }; #endif /* CONCRETECLASS_H_ */
ConcreteClass.cpp:
#include "ConcreteClass.h" CConcreteClass::CConcreteClass() { // TODO Auto-generated constructor stub cout << "concrete class construct" << endl; } CConcreteClass::~CConcreteClass() { // TODO Auto-generated destructor stub cout << "concrete class destruct" << endl; } int CConcreteClass::Stat() { cout << "ConcreteClass::Stat()" << endl; }
TemplateMethodMain.cpp:
#include <iostream> #include "AbstractClass.h" #include "ConcreteClass.h" using namespace std; int main() { CAbstractClass* pStat = new CConcreteClass(); //CConcreteClass* pStat = new CConcreteClass(); pStat->Run(); delete pStat; return 0; }
模板方法在高性能的C++异步通信框架Nebula中也有广泛应用,Nebula框架的Actor中的Cmd、Step、Session都使用了模板方法。