一.简单工厂

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

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

c++对象工厂的更多相关文章

  1. struts2的对象工厂(ObjectFactory)

    ObjectFactory,是xwork中很重要的一个类,是产生action的地方.单独使用xwork的时候,action都是这个类创建的.struts2包装了ObjectFactory,自成了一个S ...

  2. Mybatis框架基础支持层——反射工具箱之对象工厂ObjectFactory&DefaultObjectFactory(5)

    ObjectFactory官方简介:MyBatis每次创建结果集对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成. 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认 ...

  3. Javascript我学之六对象工厂函数与构造函数

    本文是金旭亮老师网易云课堂的课程笔记,记录下来,以供备忘. 概述 使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法. 然而,除了这两种常用的对象创建方式,JavaScript ...

  4. js对象工厂函数与构造函数

    转自:http://www.cnblogs.com/Jener/p/5920963.html ★概述:         使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法.然而 ...

  5. 第四章 Spring.Net 如何管理您的类___对象、对象工厂和应用程序上下文

    在前面一章我们介绍了依赖注入,控制反转的概念,以及自己动手搭建了一下Spring.Net的环境.通过这些操作,我们知道了Spring.Net 的核心是使用依赖注入或控制反转这种思想来管理业务对象,降低 ...

  6. JS构造函数、对象工厂、原型模式

    1.对象创建的3中方法 1.1.对象字面量 var obj = { name: "mingzi", work: function () { console.log("wo ...

  7. MyBatis配置文件(五)--objectFactory对象工厂

    我们在使用MyBatis执行查询语句的时候,通常都会有一个返回类型,这个是在mapper文件中给sql增加一个resultType(或resultMap)属性进行控制.resultType和resul ...

  8. Objective-C设计模式——工厂方法模式virtual constructor(对象创建)

    工厂方法模式 工厂方法模式可以控制对象的创建过程,屏蔽对象创建的细节,可以直接创建出我们所需要的已经配置好的对象. 工厂方法模式定义了创建方法的接口,让子类决定实例化哪一个类,工厂方法模式使得一个类的 ...

  9. 面向对象+闭包+三种对象的声明方式(字面式、new Object、构造函数、工厂模式、原型模式、混合模式)

    面向对象: 对代码的一种抽象,对外统一提供调用接口的编程思想 对象的属性:事物自身拥有的东西 对象的方法:事物的功能 对象:事物的一个实例 对象的原型:.prototype -> 内存地址 -& ...

随机推荐

  1. javascript 练习题目答案1

    以下是这个教程的答案 https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143 ...

  2. Linux 文件查找命令详解

    find命令 Linux find命令用来在指定目录下查找文件.任何位于参数之前的字符串都将被视为欲查找的目录名.如果使用该命令时,不设置任何参数,则find命令将在当前目录下查找子目录与文件.并且将 ...

  3. matplotlib画图

    matplotlib画图 import numpy as np import matplotlib.pyplot as plt x1=[20,33,51,79,101,121,132,145,162, ...

  4. log4j2 使用详解

    转载自 Blog of 天外的星星: http://www.cnblogs.com/leo-lsw/p/log4j2tutorial.html Log4j 2的好处就不和大家说了,如果你搜了2,说明你 ...

  5. python 全栈开发,Day50(Javascript简介,第一个JavaScript代码,数据类型,运算符,数据类型转换,流程控制,百度换肤,显示隐藏)

    一.Javascript简介 Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) Jav ...

  6. JQUery利用Uploadify插件实现文件异步上传(十一)

    一:简介: Uploadify是JQuery的一个上传插件,实现的效果非常好,带进度显示 ,且Ajax异步,能一次性上传多个文件,功能强大,使用简单 1.支持单文件或多文件上传,可控制并发上传的文件数 ...

  7. [转] 为什么javascript是单线程的却能让AJAX异步调用?

    为什么JavaScript是单线程的却能让AJAX异步发送和回调请求,还有setTimeout也看起来像是多线程的? function foo() { console.log( 'first' ); ...

  8. 敌兵布阵 HDU1166

    基础线段树 #include<cstdio> #include<iostream> using namespace std; int n,p,a,b,m,x,y,ans; st ...

  9. Ancient Printer

    为找规律题  结果为   节点数*2-最长字段+字段个数 结点不能设置为0   与判断条件相冲突 #include<bits/stdc++.h> using namespace std; ...

  10. Java采用Hibernate连接MySQL

    现有环境: Java JDK1.8 MySQL5.7 [ps]本文是很早前的基于隐马尔科夫模型进行中文词性标注的后续升级完善版,任务就是将之前的写入文件的模型参数写入MySQL 下载Hibernate ...