• 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与对应的对象类型。从而将对应的创建工厂注册到总工厂中。

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

  • 相关阅读:
    Go使用dlv调试代码
    1660 super安装tensorflow1.15
    SQL Server高级进阶之表分区删除
    SQL Server高级进阶之分区表创建
    SQL Server高级进阶之索引优化查询
    SQL Server高级进阶之索引碎片维护
    C# WinForm通用自动更新器
    获取当前月第一天,当前月最后一天,上个月日期,上个月的第一天
    去除checkbox选择的三种方式
    用SpringBoot实现策略模式
  • 原文地址:https://www.cnblogs.com/kevonyang/p/6259922.html
Copyright © 2020-2023  润新知