天天看点

C++ 设计模式(四)----原型模式

什么是原型模式?

          先来看个例子:每年的校园招聘的时候,许多好公司来学校招应届生,大家就要去投简历,我相信大家都是聪明人,先写好一份原始简历,拿去复印n多份,然后去参加宣讲会投简历,投完简历后,第二天发现要简历写牛B点,就去修改原始简历,然后再去打印n多份就可以了。其中原始简历就是原型模式中的原型。

          那么原型的模式意图呼之欲出:用原型实例指定创建对象的种类,并且通过拷贝(复制)这些原型创建新的对象。

          在GOF的《设计模式:可复用面向对象软件的基础》中是这样说的:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。这这个定义中,最重要的一个词是“拷贝”,也就是口头上的复制,而这个拷贝,也就是原型模式的精髓所在。

#include <iostream>
using namespace std;

class Prototype
{
public:
   Prototype(){}
   ~Prototype(){}

   virtual Prototype *clone() = 0;
};

class ConcretePrototypeA :public Prototype
{
public:
  ConcretePrototypeA() :member(0){}
  ~ConcretePrototypeA(){}

  ConcretePrototypeA(const ConcretePrototypeA &rhs)
  {
    member = rhs.member;
  }

  virtual ConcretePrototypeA* clone()
  {
    cout << "copy of self" << endl;
    return new ConcretePrototypeA(*this);
  }

private:
  int member;
};

int main(int argc, char **argv)
{
  //生成对像
  ConcretePrototypeA *conPro = new ConcretePrototypeA();

  //复制自身
  ConcretePrototypeA * conPro1 = conPro->clone();

  //复制自身
  ConcretePrototypeA * conPro2 = conPro->clone();

  delete conPro;
  conPro = NULL;

  delete conPro1;
  conPro1 = NULL;

  delete conPro2;
  conPro2 = NULL;

  return 0;
}      

上述代码实现了一个最简单的原型模式,但是已经将原型模式的基本实现原理展现出来了。而有的时候,当调用Clone获得了一个复制的对象以后,需要改变对象的状态,此时就可能需要在ConcretePrototype类中添加一个Initialize操作,专门用于初始化克隆对象。由于在clone的内部调用的是复制构造函数,而此处又涉及到深复制和浅复制的问题。所以,在实际操作的过程中,这些问题,都需要进行仔细的考虑。

来看一个稍微复杂点的例子:类含有指针成员,这里就涉及到了拷贝构造函数的深拷贝。其实这里例子还需要一个拷贝复制函数,很简单,就是要考虑到自赋值的情况就可以了。

#include <iostream>
using namespace std;

class Resume
{
public:
  Resume(){}

  virtual Resume* clone() =0;
  virtual void show() {};

  virtual ~Resume(){}

protected:
  char*name;
};

class ResumeA : public Resume
{
public:

  ResumeA(){}

  ResumeA(const char *str)  //构造函数  
  {
    if (str == NULL)
    {
      name = new char[1];
      name[0] = '\0';
    }
    else
    {
      name = new char[strlen(str) + 1];
      strcpy(name, str);
    }
  }

  ResumeA(const ResumeA &rhs) //拷贝构造函数  
  {
    name = new char[strlen(rhs.name) + 1];
    strcpy(name, rhs.name);
  }
                
  ResumeA& operator=(const ResumeA& rhs)
  {
    if (this == &rhs)
      return *this;
    delete[] name;
    int len = strlen(rhs.name);
    name = new char[len + 1];
    strcpy(name, rhs.name);
    return *this;
  }

   ResumeA* clone() override  
  {
    cout << "ResumeA name : " << name << endl;
    return new ResumeA(this->name);
  }

   ~ResumeA()
   {
     delete[] name;
   }
};

int main()
{
  Resume *r = new ResumeA("a");

  Resume *r1 = r->clone();
   
  delete r1;
  r1 = NULL;

}      

总结:

继续阅读