原型设计模式示例(C++)

Prototype design pattern example (c++)

我正在学习原型设计模式,但对 this article by sourcemaking 上的示例感到困惑。

class Stooge
{
public:
   virtual void slap_stick() = 0;
   virtual Stooge* clone() = 0;
};

class Larry : public Stooge
{
public:
   void slap_stick()
   {
      cout << "Larry: poke eyes\n";
   }
   Stooge*   clone() { return new Larry; }   
};
class Moe : public Stooge
{
public:
   void slap_stick()
   {
      cout << "Moe: slap head\n";
   }
   Stooge*   clone() { return new Moe; }   
};
class Curly : public Stooge
{
public:
   void slap_stick()
   {
      cout << "Curly: suffer abuse\n";
   }
   Stooge*   clone() { return new Curly; }
};

class Factory
{
public:
   static Stooge* make_stooge( int choice );
private:
   static Stooge* s_prototypes[4];
};

Stooge* Factory::s_prototypes[] = {0, new Larry, new Moe, new Curly};

Stooge* Factory::make_stooge( int choice )
{
   return s_prototypes[choice]->clone();
}

int main()
{
   vector roles;
   int    choice;

   while (true)
   {
      cout << "Larry(1) Moe(2) Curly(3) Go(0): ";
      cin >> choice;
      if (choice == 0)
         break;
      roles.push_back(Factory::make_stooge( choice ) );
   }

   for (int i=0; i < roles.size(); ++i)
      roles[i]->slap_stick();
   for (int i=0; i < roles.size(); ++i)
      delete roles[i];
}

根据原型设计模式描述

根据this。原型设计模式是一种设计模式,用于通过复制或克隆现有对象的属性来实例化 class。

据我所知,复制一个class的正常方法是使用复制构造函数,重载运算符=,或实现克隆函数通过复制现有对象的所有属性来实例化一个新对象对象。

在上面的例子中,我没有看到它是如何通过复制原型来创建新对象的,也没有复制构造函数,既没有重载运算符=,也没有定义适当的克隆函数。

那么我可以假设这不是原型设计模式的实现吗?或者我的假设有误,不理解这个例子?

编辑: 正如@songyuanyao提到的

In the example, it's creating new objects newly, without copying anything

所以我认为上面的例子不适合作为原型模式的例子,因为它不代表原型模式的主要目标。

首先,没有必要克隆一个在其上调用方法的对象,完全有可能你有一个 ManagerFactory 有一个用于克隆对象的方法即:

Object Factory::clone( Object &){

}

此外,您确实可以使用复制构造函数,但复制构造函数的缺点是它仅适用于具体类。如果,为了好的设计决策,您只向用户提供对象 API(接口/纯虚拟),那么您不能在客户端使用复制构造函数,因此如果预期用途是克隆一个项目,您可以解决这个问题通过添加 Clone 方法

class BaseVirtualClass{
public:
    virtual int foo() = 0;
    virtual BaseVirtualClass * clone() = 0;
    virtual ~BaseVirtualClass(){}
};

class DerivedClass: public BaseVirtualClass{
    int state;
public:
    DerivedClass(int a):state(a){}
    DerivedClass( const DerivedClass & other)
        : state(other.state){}
    int foo(){ // override
        return state;
    }

    BaseVirtualClass * clone(){ //override
         // I'm using copy constructor here, but hidden from user
         return new DerivedClass( *this);
    }
};

用法:

BaseVirtualClass * obj = factory.createObject();
BaseVirtualClass * clone = obj->clone();

有时你还想通过工厂来做:

BaseVirtualClass * obj = factory.createObject();
BaseVirtualClass * clone = factory.clone(obj);

注意: 除了在您仅提供指向抽象 类 的指针时修复丢失的复制构造函数外,Clone 方法有明确的意图复制一个对象状态创建 Deep Copy,而无需编写样板代码来重新创建处于该特定状态的对象。当创建对象的责任不属于对象(因为你必须使用带有自定义分配器或其他复杂依赖项的工厂)时,克隆方法将移至工厂。


编辑:

提问者在互联网上找到的代码示例在我看来是一个边缘案例。 这些对象在技术上是克隆(它们没有状态,除了类型,因此它们具有相同的状态),但我认为这不是原型模式的一个很好的例子:

  1. 当存在具有 有趣状态 的复杂对象需要以某种方式复制 时,我想使用原型模式。
  2. 最重要的部分是状态的复制,因此内部实现也应该明确说明(保留具有相同状态的对象对于内部文档来说可能不清楚目的)