什麼是原型模式?
先來看個例子:每年的校園招聘的時候,許多好公司來學校招應屆生,大家就要去投履歷,我相信大家都是聰明人,先寫好一份原始履歷,拿去影印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;
}
總結: