C++ 可配置的类工厂
项目中常用到工厂模式,工厂模式可以把创建对象的具体细节封装到Create函数中,减少重复代码,增强可读和可维护性。传统的工厂实现如下:
class Widget
{
public:
virtual int Init()
{
printf("Widget Init");
return ;
}
}; class WidgetA : public Widget
{
public:
virtual int Init()
{
printf("WidgetA Init");
return ;
}
}; class WidgetB : public Widget
{
public:
virtual int Init()
{
printf("WidgetB Init");
return ;
}
}; class IWidgetFactory
{
public:
virtual Widget *CreateWidget() = ;
}; class WidgetFactoryA : public IWidgetFactory
{
public:
virtual Widget *CreateWidget()
{
Widget *p = new WidgetA();
p->Init();
return p;
}
}; class WidgetFactoryB : public IWidgetFactory
{
public:
virtual Widget *CreateWidget()
{
Widget *p = new WidgetB();
p->Init();
return p;
}
}; int main()
{
IWidgetFactory *factoryA = new WidgetFactoryA();
Widget *widgetA = factoryA->CreateWidget();
IWidgetFactory *factoryB = new WidgetFactoryB();
Widget *widgetB = factoryB->CreateWidget(); return ;
}
假设有类WidgetA,WidgetB继承自Widget,我们可以创建WidgetFactoryA和WidgetFactoryB,根据需要用factoryA对象或factoryB对象创建对应的对象。这样的方式可以满足大多数的需求。
现在假如有这样一种需求,我们需要根据配表来生成相应的对象。比如配表中配了值1,希望生成WidgetA,值2,希望生成WidgetB。此时如果还是上述的方法,可能我们只能判断值如果为1,就用factoryA,如果为2则用factoryB。如果有WidgetA-WidgetZ,我们肯定不希望一个个用ifelse做判断。
因此这里建立一个从type值到对象的工厂映射。只要事先注册好,就可以直接从配表读取数据,并根据type值直接创建对应的对象类型。
class WidgetFactoryImplBase;
class WidgetFactory
{
public:
typedef std::map<int, WidgetFactoryImplBase*> FactoryImplMap;
static WidgetFactory &Instance()
{
static WidgetFactory factory;
return factory;
} void RegisterFactoryImpl(int type, WidgetFactoryImplBase *impl)
{
factory_impl_map_.insert(std::make_pair(type, impl));
}
Widget *CreateWidget(int type);
private:
FactoryImplMap factory_impl_map_;
}; class WidgetFactoryImplBase
{
public:
WidgetFactoryImplBase(int type)
{
WidgetFactory::Instance().RegisterFactoryImpl(type, this);
}
~WidgetFactoryImplBase()
{}
virtual Widget *CreateWidget() = ;
}; template<int type, class WidgetType>
class WidgetFactoryImpl : WidgetFactoryImplBase
{
public:
WidgetFactoryImpl() : WidgetFactoryImplBase(type)
{}
~WidgetFactoryImpl()
{}
virtual Widget *CreateWidget()
{
WidgetType *p = new WidgetType();
p->Init();
return p;
}
}; Widget *WidgetFactory::CreateWidget(int type)
{
auto it = factory_impl_map_.find(type);
if (it == factory_impl_map_.end()) return NULL;
return it->second->CreateWidget();
} #define DECLARE_WIDGET(type, WidgetType) \
static WidgetFactoryImpl<type, WidgetType> o_WidgetFactory_##type DECLARE_WIDGET(, Widget);
DECLARE_WIDGET(, WidgetA);
DECLARE_WIDGET(, WidgetB); int main()
{
WidgetFactory::Instance().CreateWidget();
WidgetFactory::Instance().CreateWidget();
return ;
}
由于工厂的Create函数大同小异,首先用模板类来定义特定值对应特定对象的工厂,如果WidgetC的创建过程和一般的不一致,再创建特化类,就省去了对每个对象类写工厂类的过程。然后将这些工厂在构造时自动注册到一个总的WidgetFactory中。真正创建时只需要调用总工厂的Create函数,传入配表等传入的type值,即可创建对应的对象。
注意这里用了一个DECLARE_WIDGET宏,来绑定type与对应的对象类型。从而将对应的创建工厂注册到总工厂中。
此方法的逻辑简单,也很好理解,在最近的游戏活动功能中,获得了非常好的效果。由于活动的类型多达几十种,为每一种活动写工厂类和根据配表值做判断会非常繁琐,也容易出错,利用了这样的工厂注册方法后,新加一个活动类型只要加一行注册代码即可搞定,且不会出错。这里把工厂注册机制分享出来,希望对大家有所帮助。
C++ 可配置的类工厂的更多相关文章
- "检索COM类工厂中 CLSID为 {00024500-0000-0000-C000-000000000046}的组件时失败,原因是出现以下错误: 80070005" 问题的解决
一.故障环境 Windows 2008 .net 3.0 二.故障描述 调用excel组件生成excel文档时页面报错.报错内容一大串,核心是"检索COM类工厂中 CLSID为 {000 ...
- 检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005
检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005 在CSDN上总是有网友问这个 ...
- [备忘]检索 COM 类工厂中 CLSID 为 {91493441-5A91-11CF-8700-00AA0060263B} 的组件时失败解决方法
检索 COM 类工厂中 CLSID 为 {91493441-5A91-11CF-8700-00AA0060263B} 的组件时失败,原因是出现以下错误: 80070005 在CSDN上总是有网友问这个 ...
- 检索 COM 类工厂中 CLSID 解决办法
我的服务器:windows server 2008(64位)+microsoft office 2007 企业版+windows服务应用程序 业务:调用msdn提供的SaveAsPDFandXPS.e ...
- 解决Office互操作错误"检索COML类工厂中 CLSID为 {xxx}的组件时失败,原因是出现以下错误: 80070005"
Excel为例(其他如Word也适用)文件数据导入时报出以下错误: 检索COML类工厂中 CLSID为 {00024500-0000-0000-C000-000000000046}的组件时失败,原因是 ...
- 【原创】asp.net导出word 检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件失败,原因是出现以下错误: 8000401a
我的服务器:windows server 2008(64位)+microsoft office 2007 企业版 业务:网站导出应聘word简历. 出现以下错误: 检索 COM 类工厂中 CLSID ...
- C#操作word或excel及水晶报表,检索 COM 类工厂中 CLSID 为 {} 的组件时失败,原因是出现以下错误: 80070005
解决办法一:<转自http://www.cnblogs.com/Sue_/articles/2123372.html> 具体解决方法如下: 1:在服务器上安装office的Excel软件. ...
- (原创)解决Excel 互操作错误"检索COML类工厂中 CLSID为 {00024500-0000-0000-C000-000000000046}的组件时失败,原因是出现以下错误: 80070005"
最近在.net中处理Excel文件数据导入时报出以下错误: 检索COML类工厂中 CLSID为 {00024500-0000-0000-C000-000000000046}的组件时失败,原因是出现以下 ...
- 索 COM 类工厂中 CLSID 为{00024500-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005。
具体解决方法如下: 1:在服务器上安装office的Excel软件. 2:在"开始"->"运行"中输入dcomcnfg.exe启动"组件服务&q ...
随机推荐
- ABP文档 - SignalR 集成
文档目录 本节内容: 简介 安装 服务端 客户端 连接确立 内置功能 通知 在线客户端 帕斯卡 vs 骆峰式 你的SignalR代码 简介 使用Abp.Web.SignalR nuget包,使基于应用 ...
- PowerShell过滤文件中的重复内容
Get-Content -Path E:\test11\data.txt | Sort-Object | Get-Unique 源文件: AA0001 2014-06-30 15:27:13.073 ...
- Hawk 5. 数据库系统
Hawk在设计之初,就是以弱schema风格定义的.没有严格的列名和列属性.用C#这样的静态强类型语言编写Hawk,其实并不方便.但弱schema让Hawk变得更灵活更强大. 因此,Hawk虽然之前支 ...
- [.NET] C# 知识回顾 - 委托 delegate (续)
C# 知识回顾 - 委托 delegate (续) [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6046171.html 序 上篇<C# 知识回 ...
- 尝试asp.net mvc 基于controller action 方式权限控制方案可行性
微软在推出mvc框架不久,短短几年里,版本更新之快,真是大快人心,微软在这种优秀的框架上做了大量的精力投入,是值得赞同的,毕竟程序员驾驭在这种框架上,能够强力的精化代码,代码层次也更加优雅,扩展较为方 ...
- 关于Visual Studio 未能加载各种Package包的解决方案
问题: 打开Visual Studio 的时候,总提示未能加载相应的Package包,有时候还无法打开项目,各种提示 解决方案: 进入用户目录 C:\Users\用户名\AppData\Local\M ...
- Android 工具-adb
Android 工具-adb 版权声明:本文为博主原创文章,未经博主允许不得转载. Android 开发中, adb 是开发者经常使用的工具,是 Android 开发者必须掌握的. Android D ...
- C#与C++通信
# C#与C++相互发送消息 # ## C#端: ## namespace CshapMessage { /// /// MainWindow.xaml 的交互逻辑 /// public partia ...
- 【C#公共帮助类】 ToolsHelper帮助类
这个帮助类,目前我们只用到了两个,我就先更新这两个,后面有用到的,我会继续更新这个Helper帮助类 在Tools.cs中 有很多方法 跟Utils里是重复的,而且Utils里的方法更加新一点,大家可 ...
- 如何搭建git服务器
一.前言 现在越来越多的公司用git进行版本控制,不过git是默认是开源的,如果私有的话是需要付费的,如果不想付费自己可以搭建一个git服务器用来版本控制. 二.服务器端操作 1.安装git sudo ...