惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
有赞技术团队
有赞技术团队
T
The Blog of Author Tim Ferriss
F
Fortinet All Blogs
D
DataBreaches.Net
F
Full Disclosure
腾讯CDC
博客园 - 【当耐特】
MyScale Blog
MyScale Blog
Stack Overflow Blog
Stack Overflow Blog
小众软件
小众软件
Hugging Face - Blog
Hugging Face - Blog
Last Week in AI
Last Week in AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
爱范儿
爱范儿
The GitHub Blog
The GitHub Blog
Engineering at Meta
Engineering at Meta
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
SegmentFault 最新的问题
The Register - Security
The Register - Security
WordPress大学
WordPress大学
博客园 - 聂微东
雷峰网
雷峰网
J
Java Code Geeks
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Privacy International News Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
A
Arctic Wolf
Scott Helme
Scott Helme
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Tor Project blog
博客园 - 三生石上(FineUI控件)
Know Your Adversary
Know Your Adversary
AWS News Blog
AWS News Blog
G
Google Developers Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
CERT Recently Published Vulnerability Notes
O
OpenAI News
Project Zero
Project Zero
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Application and Cybersecurity Blog
Application and Cybersecurity Blog
云风的 BLOG
云风的 BLOG
N
News and Events Feed by Topic
MongoDB | Blog
MongoDB | Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Microsoft Security Blog
Microsoft Security Blog
Cisco Talos Blog
Cisco Talos Blog
P
Palo Alto Networks Blog
Schneier on Security
Schneier on Security

博客园 - Clingingboy

冒个泡,刷刷存在感 使用文件映射和信号量来进程间通信 Xperf Basics: Recording a Trace (the easy way)(转) Xperf Basics: Recording a Trace(转) Xperf Analysis Basics(转) Android相关sdk使用 Uniscribe文字自动换行 Chrome RenderText分析(2) c++智能指针 codepage IMLangCodePages GUI 快捷键的实现思路 Menu实现逻辑 控件保持多种绘图状态的做法 2个函数宏技巧 绘图 Painter转接口封装的方式 DirectUI消息循环的简单封装 c++以代理的方式来实现接口化编程 使用模板来解决接口继承问题 VC++ 使用attributes定义接口
c++对象工厂
Clingingboy · 2013-11-04 · via 博客园 - Clingingboy

一.简单工厂

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

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