C++ 可配置的类工厂

  项目中常用到工厂模式,工厂模式可以把创建对象的具体细节封装到Create函数中,减少重复代码,增强可读和可维护性。传统的工厂实现如下:

 1 class Widget
 2 {
 3 public:
 4     virtual int Init()
 5     {
 6         printf("Widget Init");
 7         return 0;
 8     }
 9 };
10
11 class WidgetA : public Widget
12 {
13 public:
14     virtual int Init()
15     {
16         printf("WidgetA Init");
17         return 0;
18     }
19 };
20
21 class WidgetB : public Widget
22 {
23 public:
24     virtual int Init()
25     {
26         printf("WidgetB Init");
27         return 0;
28     }
29 };
30
31
32 class IWidgetFactory
33 {
34 public:
35     virtual Widget *CreateWidget() = 0;
36 };
37
38 class WidgetFactoryA : public IWidgetFactory
39 {
40 public:
41     virtual Widget *CreateWidget()
42     {
43         Widget *p = new WidgetA();
44         p->Init();
45         return p;
46     }
47 };
48
49 class WidgetFactoryB : public IWidgetFactory
50 {
51 public:
52     virtual Widget *CreateWidget()
53     {
54         Widget *p = new WidgetB();
55         p->Init();
56         return p;
57     }
58 };
59
60
61 int main()
62 {
63     IWidgetFactory *factoryA = new WidgetFactoryA();
64     Widget *widgetA = factoryA->CreateWidget();
65     IWidgetFactory *factoryB = new WidgetFactoryB();
66     Widget *widgetB = factoryB->CreateWidget();
67
68     return 0;
69 }

  假设有类WidgetA,WidgetB继承自Widget,我们可以创建WidgetFactoryA和WidgetFactoryB,根据需要用factoryA对象或factoryB对象创建对应的对象。这样的方式可以满足大多数的需求。

  现在假如有这样一种需求,我们需要根据配表来生成相应的对象。比如配表中配了值1,希望生成WidgetA,值2,希望生成WidgetB。此时如果还是上述的方法,可能我们只能判断值如果为1,就用factoryA,如果为2则用factoryB。如果有WidgetA-WidgetZ,我们肯定不希望一个个用ifelse做判断。

  因此这里建立一个从type值到对象的工厂映射。只要事先注册好,就可以直接从配表读取数据,并根据type值直接创建对应的对象类型。

 1 class WidgetFactoryImplBase;
 2 class WidgetFactory
 3 {
 4 public:
 5     typedef std::map<int, WidgetFactoryImplBase*> FactoryImplMap;
 6     static WidgetFactory &Instance()
 7     {
 8         static WidgetFactory factory;
 9         return factory;
10     }
11
12     void RegisterFactoryImpl(int type, WidgetFactoryImplBase *impl)
13     {
14         factory_impl_map_.insert(std::make_pair(type, impl));
15     }
16     Widget *CreateWidget(int type);
17 private:
18     FactoryImplMap factory_impl_map_;
19 };
20
21 class WidgetFactoryImplBase
22 {
23 public:
24     WidgetFactoryImplBase(int type)
25     {
26         WidgetFactory::Instance().RegisterFactoryImpl(type, this);
27     }
28     ~WidgetFactoryImplBase()
29     {}
30     virtual Widget *CreateWidget() = 0;
31 };
32
33 template<int type, class WidgetType>
34 class WidgetFactoryImpl : WidgetFactoryImplBase
35 {
36 public:
37     WidgetFactoryImpl() : WidgetFactoryImplBase(type)
38     {}
39     ~WidgetFactoryImpl()
40     {}
41     virtual Widget *CreateWidget()
42     {
43         WidgetType *p = new WidgetType();
44         p->Init();
45         return p;
46     }
47 };
48
49 Widget *WidgetFactory::CreateWidget(int type)
50 {
51     auto it = factory_impl_map_.find(type);
52     if (it == factory_impl_map_.end()) return NULL;
53     return it->second->CreateWidget();
54 }
55
56 #define DECLARE_WIDGET(type, WidgetType) 57     static WidgetFactoryImpl<type, WidgetType> o_WidgetFactory_##type
58
59 DECLARE_WIDGET(0, Widget);
60 DECLARE_WIDGET(1, WidgetA);
61 DECLARE_WIDGET(2, WidgetB);
62
63 int main()
64 {
65     WidgetFactory::Instance().CreateWidget(1);
66     WidgetFactory::Instance().CreateWidget(2);
67     return 0;
68 }

  由于工厂的Create函数大同小异,首先用模板类来定义特定值对应特定对象的工厂,如果WidgetC的创建过程和一般的不一致,再创建特化类,就省去了对每个对象类写工厂类的过程。然后将这些工厂在构造时自动注册到一个总的WidgetFactory中。真正创建时只需要调用总工厂的Create函数,传入配表等传入的type值,即可创建对应的对象。

  注意这里用了一个DECLARE_WIDGET宏,来绑定type与对应的对象类型。从而将对应的创建工厂注册到总工厂中。

  此方法的逻辑简单,也很好理解,在最近的游戏活动功能中,获得了非常好的效果。由于活动的类型多达几十种,为每一种活动写工厂类和根据配表值做判断会非常繁琐,也容易出错,利用了这样的工厂注册方法后,新加一个活动类型只要加一行注册代码即可搞定,且不会出错。这里把工厂注册机制分享出来,希望对大家有所帮助。

时间: 2024-10-18 13:18:45

C++ 可配置的类工厂的相关文章

[备忘]检索 COM 类工厂中 CLSID 为 {91493441-5A91-11CF-8700-00AA0060263B} 的组件时失败解决方法

检索 COM 类工厂中 CLSID 为 {91493441-5A91-11CF-8700-00AA0060263B} 的组件时失败,原因是出现以下错误: 80070005 在CSDN上总是有网友问这个问题,自己也遇到过,因些写出来供参考: 症状: oWordApplic = New Word.Application 当程序运行到这句时出现下面的错误: 检索 COM 类工厂中 CLSID 为 {91493441-5A91-11CF-8700-00AA0060263B} 的组件时失败,原因是出现以下

Project下载提示检索 COM 类工厂中 CLSID 为 {36D27C48-A1E8-11D3-BA55-00C04F72F325} 的组件失败

做后台系统导出Project时,部署到服务器提示:检索 COM 类工厂中 CLSID 为 {36D27C48-A1E8-11D3-BA55-00C04F72F325} 的组件失败,原因是出现以下错误: 8000401a 因为配置标识不正确,系统无法开始服务器进程.请检查用户名和密码. (异常来自 HRESULT:0x8000401A).本地测试没有问题,经过网上查询解决如下, 1:在服务器上安装office的Project软件.2:在"开始"->"运行"中输入

检索COM 类工厂中CLSID 为 {00024500-0000-0000-C000-000000000046}的组件时失败

检索COM 类工厂中CLSID 为 {00024500-0000-0000-C000-000000000046}的组件时失败 在项目中将数据导出为Excel格式时出现“检索COM 类工厂中CLSID 为 {00024500-0000-0000-C000-000000000046}的组件时失败,原因是出现以下错误: 80070005”,从网上搜了一下有如下解决方案: 1:在服务器上安装office的Excel软件. 2:在"开始"->"运行"中输入dcomcnf

检索COM类工厂中CLSID为{000209FF-0000-0000-C000-000000000046}的组件时失败,原因是出现以下错误: 80070005

http://blog.csdn.net/yiyiwyy326/archive/2007/04/30/1592657.aspx [C#]用C#动态生成Word文档之服务器配置Server 2003 收藏 用C#动态生成Word文档功能实现了,在本地的机器运行时是好的,但安装到远程服务器上就报错了,让我头疼了好久,看了很多的信息后,现在才算是搞定了. 为了不忘记特意再此做下记录来! 程序安装到远程服务器上,首先报的错误代码就是80070005(检索COM类工厂中CLSID为{000209FF-00

轻量级的.NET对象查找服务和AOP开发框架Netop.Core源码解说(3)--类工厂/对象查找服务

上节谈了谈Netop.Core的对于应用系统的配置信息的处理,对于Netop.Core最核心的服务--类工厂/对象查找服务当然要用到配置服务,等下会说到. 对于NET类工厂/对象查找服务,名气大的有Spring.Net(对应于Java的Spring--号称轻量级中间件),为什么还要再造一个轮子呢?如果说Spring是轻量级的,那Netop.Core就只 能是微量级的,够用就好,学习曲线会大幅下降,学习研究代码的时间也会大幅下降. 够用就好,何乐而不为?况且Netop.Core的类工厂/对象查找服

转 检索COM 类工厂中CLSID 为 {00024500-0000-0000-C000-000000000046}的组件时失败

检索COM 类工厂中CLSID 为 {00024500-0000-0000-C000-000000000046}的组件时失败 在项目中将数据导出为Excel格式时出现“检索COM 类工厂中CLSID 为 {00024500-0000-0000-C000-000000000046}的组件时失败,原因是出现以下错误: 80070005”,从网上搜了一下有如下解决方案: 1:在服务器上安装office的Excel软件. 2:在"开始"->"运行"中输入dcomcnf

.Net调用Office Com组件的原理及问题检索com类工厂组件检索 COM 类工厂中 CLSID 为 {XXX} 的组件失败

我是在本地32位操作系统+vs2010+office2007做创建并下载Excel,ppt文件的操作没有问题,发布到64位系统的服务器上报错,最开始报错:: 1:Retrieving the COM class factory for component with CLSID {91493441-5A91-11CF-8700-00AA0060263B} failed due to the following error: 80040154 没有注册类 (Exception from HRESUL

检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件时失败

我们给当地公安局做了个系统,在本地测试全部通过的,结果跑到客户那一个开发中一直没遇见的问题出现了:检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005.跟踪了一下,结果是将记录导出为Excel表时Excel的COM组件出错,但在VS2005里面却没有任何问题,因此得出结论,肯定是权限问题,查了下资料,问题解决.   具体解决方法如下:1:在服务器上安装office的Excel软件

检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005 【网站客户端无法读取服务器本机上的Excel】

问题描述:.NET无法读取excel 现象:执行当前 Web 请求期间,出现未处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 异常详细信息: System.UnauthorizedAccessException: 检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005. 原因: web上传到服务器,然后读取excel时,服务器端会存在c#是否有