天天看點

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;

}      

總結:

繼續閱讀