【问题标题】:How to declare factory-like method in base class?如何在基类中声明类工厂方法?
【发布时间】:2009-06-06 07:37:53
【问题描述】:

我正在寻找 C++ 类设计问题的解决方案。我想要实现的是在基类中有静态方法方法,它将返回后代类型对象的实例。关键是,其中一些应该是单例。我是用 VCL 编写的,所以可以使用 __properties,但我更喜欢纯 C++ 解决方案。

class Base {
  private:
    static Base *Instance;
  public:
    static Base *New(void);
    virtual bool isSingleton(void) = 0;
}
Base::Instance = NULL;

class First : public Base { // singleton descendant
  public:
    bool isSingleton(void) { return true; }
}

class Second : public Base { // normal descendant
  public:
    bool isSingleton(void) { return false; }
}

Base *Base::New(void) {
  if (isSingleton())
    if (Instance != NULL)
      return Instance = new /* descendant constructor */;
    else
      return Instance;
  else
    return new /* descendant constructor */;
}

出现的问题:

  • 如何声明静态变量Instance,所以它在后代类中是静态的
  • 如何在基类中调用后代构造函数

我认为按照我计划的方式克服这些问题可能是不可能的。如果是这样,我想要一些关于如何以任何其他方式解决它的建议。


编辑:代码中的一些小改动。我错过了几个指针标记。

【问题讨论】:

  • 你的意思是Instance == NULL

标签: c++ oop


【解决方案1】:

只是为了检查我们的术语是否同步 - 在我的书中,工厂类是一个类实例,它可以创建其他一些或多个类的实例。选择创建哪种类型的实例取决于工厂接收到的输入,或者至少取决于它可以检查的内容。这是一个非常简单的工厂:

class A { ~virtual A() {} };   
class B : public A {};
class C : public A {};

class AFactory {
   public:
      A * Make( char c ) {
         if ( c == 'B' ) {
             return new B;
         }
         else if ( c == 'C' ) { 
            return new C;
         }
         else {
           throw "bad type";
         }
      }
};

如果我是你,我会重新开始,记住这个例子和以下内容:

  • factorioes 不必是单例的
  • 工厂不必是静态成员
  • 工厂不必是其创建的层次结构的基类的成员
  • 工厂方法通常返回一个动态创建的对象
  • 工厂方法通常返回一个指针
  • 工厂方法需要一种方法来决定创建哪个类的实例

我不明白为什么您的工厂需要反射,而 C++ 在任何情况下都不以有意义的方式支持反射。

【讨论】:

  • 使用典型的工厂,就像您提供的那样,每当我添加新的后代类时,我都必须向 Make() 方法添加代码。这就是我认为多余和有害的,因为我想提供我的 Base 类作为一个封闭的框架。
  • 不,你没有。您可以在工厂注册新类,而无需更改工厂代码。这是一个很常见的模式——你读过一本关于这个主题的好书吗?
  • @samuil:考虑使用抽象工厂,在运行时注册具体工厂。您对抽象工厂进行一次编码(它允许注册具体工厂),然后为您希望抽象工厂创建的每个新类型创建一个新的具体工厂。这是很常见的模式。
  • @Neil Butterworth:我读过 Ruby 中的模式。 C++ 完全不同,需要更多的模式。感谢您的建议,解决方案开始出现;)
【解决方案2】:

基于@Shakedown 的回答,我将使用CRTPBase 模板化为实际类型:

template <class T>
class Base
{
public:
 static std::auto_ptr<Base<T> > construct()
 {
    return new T();
 }
};

class First : public Base<First>
{
};

class Second : public Base<Second>
{
};

这很好,因为construct 现在再次成为静态成员。你可以这样称呼它:

std::auto_ptr<First> first(First::construct());
std::auto_ptr<Second> second(Second::construct());

// do something with first and second...

【讨论】:

  • 有趣的方法。我目前正在尝试看看它是否符合我的需求,并替换 Neil Butterworth 提到的典型工厂模式。
【解决方案3】:

你可以创建一个Singleton类和一个NonSingleton类,并让所有后代继承其中一个。

class Base {
  public:
    static Base *New() = 0;
}

class SingletonDescendant: public Base { 
  public:
    *Base::New() {
      if (Instance != NULL)
        return Instance = new /* descendant constructor */;
      else
        return Instance;
    }
  private:
    static Base *Instance;
}
SingletonDescendant::Instance = NULL;

class NonSingletonDescendant: public Base { 
  public:
    *Base::New() {
      return new;
    }
}

class First : public SingletonDescendant{ // singleton descendant
}

class Second : public NonSingletonDescendant{ // normal descendant
}

解决了你提出的问题:

  • 如何声明静态变量 Instance,所以它在后代类中是静态的:它只存在于 SingletonDescendant 类中。
  • 如何在基类中调用后代构造函数:使用 New 函数
  • 我必须在每个后代中编写construct()方法;我认为它是多余的,因为它必须做什么很明显:现在它只在 SingletonDescendant 和 NonSingletonDescendant 中。

【讨论】:

  • 单例和非单例后代之间的区别看起来不错,但是您留下了我的注释 /* 后代构造函数 */。因此,无论如何我都必须为每个后代实现 New 方法。
【解决方案4】:

这样的事情怎么样:

class Base
{
public:
 virtual Base construct() = 0;
};

class First : public Base
{
public:
 Base construct(){ return First(); // or whatever constructor }
};

class Second : public Base
{
public:
 Base construct(){ return Second(...); // constructor }
};

【讨论】:

  • 我现在正在使用这种方法,但是我必须在每个后代中编写 construct() 方法——我认为它是多余的,因为它必须做什么很明显做。
  • 我认为通常的建议是调用您的“工厂”方法create(),因为它们是非常具体的 not 构造函数。
猜你喜欢
  • 1970-01-01
  • 2014-07-23
  • 2019-10-22
  • 1970-01-01
  • 1970-01-01
  • 2011-12-12
  • 2018-07-01
  • 1970-01-01
  • 2020-10-22
相关资源
最近更新 更多