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

推荐订阅源

D
Docker
爱范儿
爱范儿
T
The Exploit Database - CXSecurity.com
量子位
T
Tailwind CSS Blog
T
Threatpost
The GitHub Blog
The GitHub Blog
AWS News Blog
AWS News Blog
云风的 BLOG
云风的 BLOG
K
Kaspersky official blog
P
Proofpoint News Feed
博客园 - 司徒正美
L
LangChain Blog
T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
罗磊的独立博客
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 叶小钗
S
Secure Thoughts
The Last Watchdog
The Last Watchdog
Spread Privacy
Spread Privacy
H
Hacker News: Front Page
T
Troy Hunt's Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Google DeepMind News
Google DeepMind News
W
WeLiveSecurity
A
Arctic Wolf
Apple Machine Learning Research
Apple Machine Learning Research
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Proofpoint News Feed
T
Tor Project blog
T
The Blog of Author Tim Ferriss
I
Intezer
P
Privacy & Cybersecurity Law Blog
美团技术团队
N
Netflix TechBlog - Medium
博客园_首页
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Vulnerabilities – Threatpost
Application and Cybersecurity Blog
Application and Cybersecurity Blog
G
Google Developers Blog
Attack and Defense Labs
Attack and Defense Labs
T
Tenable Blog
月光博客
月光博客
Stack Overflow Blog
Stack Overflow Blog
J
Java Code Geeks
腾讯CDC
Microsoft Security Blog
Microsoft Security Blog
A
About on SuperTechFans
Last Week in AI
Last Week in AI

博客园 - 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)

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