基于参数在基类中创建派生类

时间:2012-11-08 16:07:25

标签: c++ design-patterns derived-class object-construction

我的问题或多或少与Need a design pattern to remove enums and switch statement in object creation的问题相同但是我没有看到抽象工厂模式在这里很适合。

我目前正计划重构/重新实现一些现有的DAL / ORM混合库。在现有代码中的某处,代码如下所示:

class Base
{
  static Base * create(struct Databasevalues dbValues)
  {
    switch(dbValues.ObjectType)
    {
    case typeA:
      return new DerivedA(dbValues);
      break;
    case typeB:
      return new DerivedB(dbValues);
      break;
    }
  }
}

class DerivedA : public Base
{
  // ...
}

class DerivedB : public Base
{
  // ...
}

因此,负责数据库通信的库使用有关数据库实体的所有信息填充结构,然后调用上述create()方法以在ORM中实际创建相应的对象。 但我不喜欢基类知道所有派生类的想法,我也不喜欢switch语句。我还想避免创建另一个类只是为了创建这些对象。您如何看待当前的方法?您将如何实现此功能?

4 个答案:

答案 0 :(得分:6)

这已经在这里讨论了数百万次。如果您不想创建单独的工厂类,则可以执行此操作。

class Base
{

public:
    template <class T>
    static void Register  (TObjectType type)
    {
       _creators[type] = &creator<T>;
    }

    static Base* Create (TObjectType type)
    {
        std::map <TObjectType, Creator>::iterator C = _creators.find (type);
        if (C != _creators.end())
          return C->second ();

        return 0;        
    }

private:
    template <class T>
    static Base* creator ()
    {
        return new T;
    }

private:
    typedef Base* (::*Creator) ();
    static std::map <TObjectType, Creator> _creators;
};

int main ()
{
   Base::Register <Derived1> (typeA);
   Base::Register <Derived2> (typeB);

   Base* a = Base::Create (typeA);
   Base* b = Base::Create (typeB);
}

答案 1 :(得分:3)

假设您使用映射替换交换机,例如map<ObjectType, function<Base* (DatabaseValues&)>>

现在,工厂(可能存在或不存在于基类中)不需要知道所有子类。

但是,地图必须以某种方式填充。这意味着要么填充它(因此你的知道所有子类问题刚被从一个地方推到另一个地方),或者你需要子类来使用静态初始化来在地图中注册它们的工厂函数。 / p>

答案 2 :(得分:1)

无论你做什么,你都需要切换案例或其他一些只隐藏类似逻辑的构造。

然而,您可以而且应该做的是从您的Base中删除create方法 - 您完全正确它不应该知道它的派生方法。此逻辑属于另一个实体,例如工厂或控制器。

答案 3 :(得分:1)

只是不要使用枚举。它们不是OO构造,这就是为什么JAVA在开始时没有它们(不幸的是压力太大而无法添加它们)。

考虑代替这样的枚举:

enum Types {
  typeA,
  typeB
};

这种结构,不需要切换(在我看来是另一种非OO结构)和地图:

<强> types.h中

class Base;
class BaseFactory {
public:
   virtual Base* create() = 0;
};     
class Types {
public:
  // possible values 
  static Types typeA;
  static Types typeB;
  // just for comparison - if you do not need - do not write...
  friend bool operator == (const Types & l, const Types & r) 
  { return l.unique_id == r.unique_id; }
  // and make any other properties in this enum equivalent - don't add them somewhere else 
  Base* create() { return baseFactory->create(); }

private:
   Types(BaseFactory* baseFactory, unsigned unique_id);
   BaseFactory* baseFactory;
   unsigned unique_id; // don't ever write public getter for this member variable!!!
};   

<强> Types.cpp

#include "Types.h"
#include "Base.h"
#include "TypeA.h"
#include "TypeB.h"

namespace {
  TypeAFactory typeAFactory;
  TypeBFactory typeAFactory;
   unsigned unique_id = 0;
}
Types Types::typeA(&typeAFactory, unique_id++);
Types Types::typeA(&typeBFactory, unique_id++);

所以你的例子(如果你真的需要这个功能):

class Base
{
  static Base * create(struct Databasevalues dbValues)
  {
    return dbValues.ObjectType.create();
  }
};

缺少零件应易于实施。