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 ...
随机推荐
- 从源码看Azkaban作业流下发过程
上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- Angular企业级开发(5)-项目框架搭建
1.AngularJS Seed项目目录结构 AngularJS官方网站提供了一个angular-phonecat项目,另外一个就是Angular-Seed项目.所以大多数团队会基于Angular-S ...
- socket读写返回值的处理
在调用socket读写函数read(),write()时,都会有返回值.如果没有正确处理返回值,就可能引入一些问题 总结了以下几点 1当read()或者write()函数返回值大于0时,表示实际从缓冲 ...
- 基于本地存储的kvm虚拟机在线迁移
基于本地存储的kvm虚拟机在线迁移 kvm虚拟机迁移分为4种(1)热迁移基于共享存储(2)热迁移基于本地存储(3)冷迁移基于共享存储(4)冷迁移基于本地存储 这里介绍的是基于本地存储的热迁移 动态块迁 ...
- 通过ProGet搭建一个内部的Nuget服务器
.NET Core项目完全使用Nuget 管理组件之间的依赖关系,Nuget已经成为.NET 生态系统中不可或缺的一个组件,从项目角度,将项目中各种组件的引用统统交给NuGet,添加组件/删除组件/以 ...
- 基于SignalR实现B/S系统对windows服务运行状态的监测
通常来讲一个BS项目肯定不止单独的一个BS应用,可能涉及到很多后台服务来支持BS的运行,特别是针对耗时较长的某些任务来说,Windows服务肯定是必不可少的,我们还需要利用B/S与windows服务进 ...
- Oracle使用触发器和mysql中使用触发器的比较——学习笔记
一.触发器 1.触发器在数据库里以独立的对象存储, 2.触发器不需要调用,它由一个事件来触发运行 3.触发器不能接收参数 --触发器的应用 举个例子:校内网.开心网.facebook,当你发一个日志, ...
- Java
2016-12-17 21:10:28 吉祥物:Duke(公爵) Logo:咖啡(爪哇岛盛产咖啡) An overview of the software development proce ...
- Object是什么
Object是什么 .Net程序员们每天都在和Object在打交道如果你问一个.Net程序员什么是Object,他可能会信誓旦旦的告诉你"Object还不简单吗,就是所有类型的基类" ...