代码改变世界

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)

现在就全部完成了整个步骤的改造,此思想可以用到很多类似的对象创建方法,很管用