我们一般使用工厂的方式如下
CMyFactory
{
CMyProduct* Create(int iProductID);
}
实现如下:
CMyProduct* Create(int iProductID)
{
switch(iProductID)
{
case 1:
return new Product1;
break;
case 2:
return new Product2;
break;
default:
break;
}
需要增加3,4时就需要再次增加switch。并且factory类能够看到所有子类,需要保护所有子类。我们碰到这种设计就需要思考下,能否出一个泛型设计,易于扩展。耦合性低呢?
新的设计方案如下,使用了前面的单件模式
代码比较简单,没有什么注释。
#pragma once
#include <map>
#include "../Singletons/Singleton.h"
using namespace std;
//
template<class AbstractProduct,
typename IdentifierType,
typename ProductCreatorFun
>
class Factory: public CSingleton<Factory<AbstractProduct, IdentifierType, ProductCreatorFun> >
{
public:
bool Register(const IdentifierType& id, ProductCreatorFun createfun)
{
return callbacks_.insert(make_pair(id, createfun)).second;
}
bool UnRegister(const IdentifierType& id)
{
return callbacks_.erase(id) == 1;
}
template<typename TListParam>
AbstractProduct* createProduct(const IdentifierType& id, TListParam param)
{
map<IdentifierType, ProductCreatorFun>::iterator it = callbacks_.find(id);
if (it == callbacks_.end())
{
return NULL;
}
return (it->second)(param);
}
AbstractProduct* createProduct(const IdentifierType& id)
{
map<IdentifierType, ProductCreatorFun>::iterator it = callbacks_.find(id);
if (it == callbacks_.end())
{
return NULL;
}
return (it->second)(param);
}
private:
std::map<IdentifierType, ProductCreatorFun> callbacks_;
};
}
测试代码如下。目前只考虑一个参数的情况,后续可以通过tuple进行任意参数扩展即可。
另外函数指针没有使用boost和C++11,使用typedef实现先。后续使用c++11还可以使用成员函数指针等
class CBaseProduct
{
};
struct TestData
{
int i;
int j;
};
typedef CBaseProduct* (*callbackfun)(TestData);
typedef Factory<CBaseProduct, int, callbackfun> testfactory;
class CDevide1: public CBaseProduct
{
friend class Factory<CBaseProduct, int, callbackfun>;
public:
static CBaseProduct* Create1(TestData aa)
{
return new CDevide1;
}
};
class CDevide2: public CBaseProduct
{
friend class Factory<CBaseProduct, int, callbackfun>;
public:
static CBaseProduct* Create2(TestData bb)
{
return new CDevide2;
}
};
void CTestObjectFactory::Test()
{
TestData aa = {0};
testfactory::Instance().Register(1, CDevide1::Create1);
testfactory::Instance().Register(2, CDevide2::Create2);
testfactory::Instance().createProduct(1, aa);
testfactory::Instance().createProduct(2, aa);
}