zoukankan      html  css  js  c++  java
  • c++对象工厂

     

    一.简单工厂

    #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)

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

  • 相关阅读:
    vue2.0路由-适合刚接触新手简单理解
    JAVA实现DES加密实现详解
    计算机网络: IP地址,子网掩码,网段表示法,默认网关,DNS服务器详解
    vue-自定义组件传
    mybatis 乐观锁和逻辑删除
    axios 全攻略之基本介绍与使用(GET 与 POST)
    PowerDesigner使用教程
    scala slick mysql utf8mb4 支持
    spring-boot jpa mysql emoji utfmb4 异常处理
    花生壳的ddns 关键时刻又掉链子,准备迁到阿里万网
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/3407662.html
Copyright © 2011-2022 走看看