c++对象工厂
一.簡單工廠
#pragma oncestruct 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)現在就全部完成了整個步驟的改造,此思想可以用到很多類似的對象創建方法,很管用
總結
- 上一篇: 恢复SQLSERVER被误删除的数据
- 下一篇: c++以代理的方式来实现接口化编程