問題描述
看到這個模式,很容易想到小時候看的《西游記》,齊天大聖孫悟空發飆的時候可以通過自己頭上的 3 根毛立馬復制出來成千上萬的孫悟空, 對付小妖怪很管用(數量最重要)。
Prototype 模式也正是提供了自我復制的功能, 就是說新對象的創建可以通過已有對象進行創建。在 C++中,拷貝構造函數( Copy Constructor) 曾經是很對程序員的噩夢,淺層拷貝和深層拷貝的魔魘也是很多程序員在面試時候的快餐和系統崩潰時候的根源之一。
在GOF的《設計模式:可復用面向對象軟件的基礎》中是這樣說的:用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。這這個定義中,最重要的一個詞是“拷貝”,也就是口頭上的復制,而這個拷貝,也就是原型模式的精髓所在。
UML類圖
由於克隆需要一個原型,而上面的類圖中Prototype就這個原型,Prototype定義了克隆自身的Clone接口,由派生類進行實現,而實現原型模式的重點就在於這個Clone接口的實現。ConcretePrototype1類和ConcretePrototype2類繼承自Prototype類,並實現Clone接口,實現克隆自身的操作;同時,在ConcretePrototype1類和ConcretePrototype2類中需要重寫默認的復制構造函數,供Clone函數調用,Clone就是通過在內部調用重寫的復制構造函數實現的。在后續的編碼過程中,如果某個類需要實現Clone功能,就只需要繼承Prototype類,然后重寫自己的默認復制構造函數就好了。好比在C#中就提供了ICloneable接口,當某個類需要實現原型模式時,只需要實現這個接口的道理是一樣的。
使用場合
原型模式和建造者模式、工廠方法模式一樣,都屬於創建型模式的一種。簡單的來說,我們使用原型模式,就是為了創建對象。不過,適合原型模式的最好選擇如下:
1.當我們的對象類型不是開始就能確定的,而這個類型是在運行期確定的話,那么我們通過這個類型的對象克隆出一個新的對象比較容易一些;
2.有的時候,我們需要一個對象在某個狀態下的副本,此時,我們使用原型模式是最好的選擇;例如:一個對象,經過一段處理之后,其內部的狀態發生了變化;這個時候,我們需要一個這個狀態的副本,如果直接new一個新的對象的話,但是它的狀態是不對的,此時,可以使用原型模式,將原來的對象拷貝一個出來,這個對象就和之前的對象是完全一致的了;
3.當我們處理一些比較簡單的對象時,並且對象之間的區別很小,可能就幾個屬性不同而已,那么就可以使用原型模式來完成,省去了創建對象時的麻煩了;
4.有的時候,創建對象時,構造函數的參數很多,而自己又不完全的知道每個參數的意義,就可以使用原型模式來創建一個新的對象,不必去理會創建的過程。
->適當的時候考慮一下原型模式,能減少對應的工作量,減少程序的復雜度,提高效率。
代碼實現
#include <iostream> #include <string> using namespace std; class Prototype { private: string str; public: Prototype(string s) { str = s; } Prototype() { str = ""; } void show() { cout << str << endl; } virtual Prototype *clone() = 0; }; class ConcretePrototype1 :public Prototype { public: ConcretePrototype1(string s) :Prototype(s) {} ConcretePrototype1(){} virtual Prototype *clone() { ConcretePrototype1 *p = new ConcretePrototype1(); *p = *this; return p; } }; class ConcretePrototype2 :public Prototype { public: ConcretePrototype2(string s) :Prototype(s) {} ConcretePrototype2(){} virtual Prototype *clone() { ConcretePrototype2 *p = new ConcretePrototype2(); *p = *this; return p; } }; int main() { ConcretePrototype1 *test = new ConcretePrototype1("小李"); ConcretePrototype2 *test2 = (ConcretePrototype2 *)test->clone(); test->show(); test2->show(); return 0; }
運行結果:
#include <iostream> #include <string> using namespace std; class Resume { private: string name,sex,age,timeArea,company; public: Resume(string s) { name=s; } void setPersonalInfo(string s,string a) { sex=s; age=a; } void setWorkExperience(string t,string c) { timeArea=t; company=c; } void display() { cout<<name<<" "<<sex<<" "<<age<<endl; cout<<"工作經歷: "<<timeArea<<" "<<company<<endl<<endl; } Resume *clone() { Resume *b; b=new Resume(name); b->setPersonalInfo(sex,age); b->setWorkExperience(timeArea,company); return b; } }; int main() { Resume *r=new Resume("李俊宏"); r->setPersonalInfo("男","26"); r->setWorkExperience("2007-2010","讀研究生"); r->display(); Resume *r2=r->clone(); r2->setWorkExperience("2003-2007","讀本科"); r->display(); r2->display(); return 0; }
運行結果:
一如既往推薦:C++設計模式——原型模式