c++对象工厂
2013-11-04 23:07 Clingingboy 阅读(2217) 评论(0) 编辑 收藏 举报
一.简单工厂
#pragma once struct IObjectA { virtual void Test1()=0; }; class ObjectA:public IObjectA { public: virtual void Test1(){} }; struct IObjectB { virtual void Test2()=0; }; class ObjectB:public IObjectB { public: virtual void Test2(){} }; class ObjectFactory { public: static void Create(int nFlag,void** ppVoid) { switch (nFlag) { case 1: { IObjectA *pA=new ObjectA; *ppVoid=pA; } break; case 2: { IObjectB *pB=new ObjectB; *ppVoid=pB; } break; } } }; class ObjectTest { public: ObjectTest(); ~ObjectTest(); static void Test1() { IObjectA *pA=nullptr; ObjectFactory::Create(1,(void**)&pA); pA->Test1(); } };
优缺点:这种工厂适用于对象不多的情况下,否则工厂类必须要知道所有类
对于一个比较大的项目如果有较多的对象就不适合了
二.使用__uuidof简化类型创建
借助这个关键字,可以为一个类指定一个guid
[ uuid("F5844C2A-50D1-4F2C-85DB-429729927F0F") ] struct IObjectA { virtual void Test1()=0; };
如下代码:
template<typename T> static T* Create() { GUID id=__uuidof(T); if(IsEqualGUID(id,__uuidof(IObjectA))) { IObjectA *pA=new ObjectA; return (T*)pA; } else if(IsEqualGUID(id,__uuidof(IObjectB))) { IObjectB *pB=new ObjectB; return (T*)pB; } return nullptr; } static void Test2() { IObjectA *pA=ObjectFactory::Create<IObjectA>(); pA->Test1(); }
以上的使用方式对外确实便利了很多
下面来解决if else的问题,
三.使用map来存储
1.由于map要使用guid来作为key,那么就需要一个比较函数
来看一下IsEqualGUID的实现,实际是一个宏,对字符串的比较
__inline int IsEqualGUID(REFGUID rguid1, REFGUID rguid2) { return !memcmp(&rguid1, &rguid2, sizeof(GUID)); }
2.为了可以灵活创建对象,我们可以使用函数指针来创建对象
基于以上2点,我们创建来以下数据结构
typedef void (*CreateFunc)(void** ppVoid); struct guidCompare { bool operator () (GUID rguid1,GUID rguid2) const { return memcmp(&rguid1, &rguid2, sizeof(GUID))< 0; } }; static std::map<GUID,CreateFunc,guidCompare> m_mapObj;
接着要初始化各个对象的创建函数
template<typename T,typename I> static void CreateInstance(void** ppVoid) { I *pObject=new T; *ppVoid=pObject; } static void Init() { m_mapObj.insert(std::map<GUID,CreateFunc>::value_type (__uuidof(IObjectA),CreateInstance<ObjectA,IObjectA>)); m_mapObj.insert(std::map<GUID,CreateFunc>::value_type (__uuidof(IObjectB),CreateInstance<ObjectB,IObjectB>)); }
3.再次改造一个Create方法
template<typename T> static T* CreateFromMap() { GUID id=__uuidof(T); std::map<GUID,CreateFunc>::iterator iter=m_mapObj.find(id); if(iter!=m_mapObj.end()) { T* pObject=NULL; iter->second((void**)&pObject); return pObject; } return nullptr; }
4.测试代码
static void Test3() { ObjectFactory::Init(); IObjectA *pA=ObjectFactory::CreateFromMap<IObjectA>(); pA->Test1(); }
以上步骤不再用一个一个的判断对象的guid,唯一的问题点在于初始化的问题
四.借助全局对象初始化来注册
封装一个Register方法
template<typename T,typename I> static void Register() { m_mapObj.insert(std::map<GUID,CreateFunc>::value_type (__uuidof(I),CreateInstance<T,I>)); } Register<ObjectA,IObjectA>();
如果直接全局来调用这个方法的话显的有些暴力,而且容易出错,重复注册,可以借助一个辅助类在构造函数内完成
class ObjectACreateHelper { public: ObjectACreateHelper() { ObjectFactory::Register<ObjectA,IObjectA>(); } }; class ObjectBCreateHelper { public: ObjectBCreateHelper() { ObjectFactory::Register<ObjectB,IObjectB>(); } }; ObjectACreateHelper g_ObjectACreateHelper; ObjectBCreateHelper g_ObjectBCreateHelper;
上面的代码就完成的差不多了,上面的代码就是力气活来,可以再想办法简化
五.使用宏和模板来简化注册
template<typename T,typename I> class CObjectCreateHelper { public: CObjectCreateHelper() { ObjectFactory::Register<T,I>(); } }; #define REG_CREATEObject(T, I) CObjectCreateHelper<T,I> g_##T; REG_CREATEObject(ObjectA,IObjectA) REG_CREATEObject(ObjectB,IObjectB)
现在就全部完成了整个步骤的改造,此思想可以用到很多类似的对象创建方法,很管用