wangwu
有一个基类
TypeHandlerBase
,还有一批继承了它的子类:
DataHandler
、
NameHandler
、... ,他们被用来处理不同类型的数据,比如
NameHandler
逐行解析名字,把名打印出来。
DataHandler
逐行解析日期,把日期插入不同的数据库。这些类都实现了
process(file)
函数,该函数负责完成上诉处理数据的流程
如果使用常规做法,就是读取第一行,然后一堆
if else
判断来
new
一个对应的
handler
,伪代码如下:
int main() {
string type
open(filename)
type = getline(filename)
TypeHandlerBase* handler
if (type == "Name") {
handler = new NameHandler()
} else if (type == "Date") {
handler = new DateHandler()
} else if ...
handler->process(filename)
如果handler子类数量过多,你的if else会变的非常长且丑陋,本文写一个根据字符串自动加载对应类的方法——动态工厂
你的程序需要做的事是:读程序的第一行,根据读出来的字符串调用对应的handler类,然后执行handler->process(file)来处理文件,使用该方法,你的调用将会变成这样,伪代码如下:
int main (filename) {
string type
open(filename)
type = getline(filename)
TypeHandlerBase* handler = DynamicFactory<TypeHandlerBase>::instance()->create(type + “Handler”)
handler->process(filename)
本篇文章教你如何写一个动态工厂实现上面的需求
首先要掌握一些知识,如果懂可以跳过
typeid关键字
typeid 返回一个变量或数据类型的“类型”。
#include <typeinfo>
namespace test{
class Myclass{ };
int main () {
cout << typeid(int).name() << endl;
cout << typeid(double).name() << endl;
cout << typeid(test::Myclass).name() << endl;
输出结果:
N4test7MyclassE
可以看到,test::Myclass通过typeid()关键字输出变成了N4test7MyclassE,这是因为编译器修饰了符号,那么怎么获取正确的名字呢?要用到cxxabi这个库
abi::__cxa_demangle获取可读类名
abi::__cxa_demangle()这个函数传入typeid就可以获得真的类名了
#include <cxxabi.h>
static std::string ReadTypeName(const char* name) {
char* real_name = abi::__cxa_demangle(name, nullptr, nullptr, nullptr);
std::string real_name_string(real_name);
free(real_name);
return real_name_string;
编写工厂类
通过上面的知识补充,我们现在可以通过一个类型T获取对应的T的名字了,我们来逐渐完善工厂类吧,工厂类DynamicFactory<TBase>用于创建TBase类派生的类型。
首先,一个工厂是一个单例,需要instence()函数,
其次,工厂类里需要有一个map成员变量, key是T名字字符串作为,value是返回基类TBase的函数指针, 我们姑且命名为create_function_map_.
然后,我们需要一个注册函数来往map里面注册我们定义的class们,就要用到上一节定义的ReadTypeName函数解析出真实的类名注册进去
最后我们再定义一个create()函数用来在map里查找类并返回函数指针并调用,创建一个对应类型的实例
template <typename TBase>
class DynamicFactory {
public:
typedef TBase* (*CreateFunction)();
static DynamicFactory* instance() {
static DynamicFactory fac;
return &fac;
bool regist(const char* name, CreateFunction func) {
if (!func) {
return false;
std::string type_name = common::ReadTypeName(name);
return create_function_map_.insert(std::make_pair(type_name, func)).second;
TBase* create(const std::string& type_name) {
typename std::map<std::string, CreateFunction>::iterator it =
create_function_map_.find(type_name);
if (it == create_function_map_.end()) {
return NULL;
return it->second();
private:
std::map<std::string, CreateFunction> create_function_map_;
好了,工厂类创建好了,我们需要用某个类的时候,可以这么获得
TypeHandlerBase* p_name_handler = DynamicFactory<TypeHandlerBase>::instance()
->create("test::NameHandler");
p_name_handler->process(file_name);
调用是好调用,但是注册怎么注册呢?下一章教大家写一种自动注册的方法
编写对象创建器
称DynamicCreate为动态创建器类,当我们要在动态工厂中注册一个子类时,只需要继承动态创建器类即可,例如NameHandler:
class NameHandler : public DynamicCreate<NameHandler, TypeHandlerBase>
动态创建器类的模板参数是<类自己的名字, 基类名>
怎么做到的呢?看DynamicCreate<T, TBase>,关键就是s_registor这个静态成员变量,利用静态变量在程序运行的时候就会初始化这个性质,在struct registor构造函数中完成了向工厂类里注册的操作。
最后别忘了在class外面对static成员变量进行声明
template <typename T, typename TBase>
class DynamicCreate : public TBase {
public:
static TBase* CreateObject() { return new T(); }
struct registor {
registor() {
if (!DynamicFactory<TBase>::instance()->regist(typeid(T).name(), CreateObject)) {
assert(false);
static registor s_registor;
public:
DynamicCreate() {}
virtual ~DynamicCreate() {}
template <typename T, typename TBase>
typename DynamicCreate<T, TBase>::registor DynamicCreate<T, TBase>::s_registor;
好啦,大功告成,再看一下静态工厂的用法:
int main (filename) {
string type
open(filename)
type = getline(filename)
TypeHandlerBase* handler = DynamicFactory<TypeHandlerBase>::instance()->create(type + “Handler”);
handler->process(filename)
当文件第一行是Name,handler会得到一个NameHandler.