1.概述
????意圖:我們將已經存在的對象作為原型,用戶可以通過復制這些原型創建新的對象。
????使用場合:當一個系統應該獨立于產品的創建、構造和表示時,可以使用原型模式。在原型模式中,產品的創建和初始化再類的Clone
方法中完成。在使用是,我們可以用一些列原型對象來代替生成相應對象的工廠對象,并且可以使拷貝、粘貼等操作獨立于需要復制的對象。
????結構:
????原型模式(Prototype):用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象。原型模式說白了就是從一個對象再創建另外一個可定制的對象,而且不需要直到任何創建的細節。
????? ????原型模式基本代碼:
????原型類:

Code
public?abstract?class?Prototype

????
{
????????private?string?id;

????????//?Constructor?
????????public?Prototype(string?id)

????????
{
????????????this.id?=?id;
????????}

????????//?Property?
????????public?string?Id

????????
{

????????????get?
{?return?id;?}
????????}

????????public?abstract?Prototype?Clone();
????}

????具體原型類:

Code
public?class?ConcretePrototype1?:?Prototype

????
{
????????//?Constructor?
????????public?ConcretePrototype1(string?id)
????????????:?base(id)

????????
{
????????}

????????public?override?Prototype?Clone()

????????
{
????????????//?Shallow?copy?
????????????return?(Prototype)this.MemberwiseClone();
????????}
????}


????public?class?ConcretePrototype2?:?Prototype

????
{
????????//?Constructor?
????????public?ConcretePrototype2(string?id)
????????????:?base(id)

????????
{
????????}

????????public?override?Prototype?Clone()

????????
{
????????????//?Shallow?copy?
????????????return?(Prototype)this.MemberwiseClone();
????????}
????}

????客戶端:

Code
????????????ConcretePrototype1?p1?=?new?ConcretePrototype1("I");
????????????ConcretePrototype1?c1?=?(ConcretePrototype1)p1.Clone();
????????????Console.WriteLine("Cloned:?{0}",?c1.Id);

????????????ConcretePrototype2?p2?=?new?ConcretePrototype2("II");
????????????ConcretePrototype2?c2?=?(ConcretePrototype2)p2.Clone();
????????????Console.WriteLine("Cloned:?{0}",?c2.Id);

????2. 實例
????對于.NET而言,原型模式抽象類Prototype是用不著的,在.NET中System命名空間中提供了ICloneable接口,其中就是唯一的一個方法Clone(),這樣我們只需要實現這個接口就可以完成原型模式了。
????下面看大話設計模式中的簡歷的原型實現:
代碼結構圖:
????簡歷類:

Code
public?class?Resume?:?ICloneable

????
{
????????private?string?name;
????????private?string?sex;
????????private?string?age;
????????private?string?timeArea;
????????private?string?company;

????????public?Resume(string?name)

????????
{
????????????this.name?=?name;
????????}

????????//設置個人信息
????????public?void?SetPersonalInfo(string?sex,?string?age)

????????
{
????????????this.sex?=?sex;
????????????this.age?=?age;
????????}
????????//設置工作經歷
????????public?void?SetWorkExperience(string?timeArea,?string?company)

????????
{
????????????this.timeArea?=?timeArea;
????????????this.company?=?company;
????????}

????????//顯示
????????public?void?Display()

????????
{
????????????Console.WriteLine("{0}?{1}?{2}",?name,?sex,?age);
????????????Console.WriteLine("工作經歷:{0}?{1}",?timeArea,?company);
????????}

????????public?Object?Clone()

????????
{
????????????return?(Object)this.MemberwiseClone();
????????}

}

????客戶端調用:

Code
static?void?Main(string[]?args)


{
????Resume?a?=?new?Resume("大鳥");
????a.SetPersonalInfo("男",?"29");
????a.SetWorkExperience("1998-2000",?"XX公司");
????Resume?b?=?(Resume)a.Clone();
????b.SetWorkExperience("1998-2006",?"YY企業");
????Resume?c?=?(Resume)a.Clone();
????c.SetPersonalInfo("男",?"24");
????a.Display();
????b.Display();
????c.Display();
????Console.Read();
}

????結果顯示:
????大鳥男 29
????工作經歷 1998-2000 XX公司
????大鳥 29
????工作經歷 1998-2006 YY公司
????大鳥男 24
????工作經歷 1998-2000 XX公司
????一般在初始化的信息不發生變化的情況下,克隆是最好的方法。這既隱藏了對象的創建細節,又對性能是大大的提高。
????下面我們來看深克隆和淺克隆:
????在上面的簡歷類中,數據都是string型的,而string是一種擁有值類型特點的特殊引用類型,MemberwiseClone()方法對于值類型的字段執行逐位復制,對于引用類型,則只復制引用的對象,因此,原對象及其副本引用同一個對象。我們看下面的引用類型的簡歷克隆的代碼實現:
????代碼結構圖:
????詳細代碼:
????工作經歷類:

Code
//工作經歷
????public?class?WorkExperience

????
{
????????private?string?workDate;
????????public?string?WorkDate

????????
{

????????????get?
{?return?workDate;?}

????????????set?
{?workDate?=?value;?}
????????}
????????private?string?company;
????????public?string?Company

????????
{

????????????get?
{?return?company;?}

????????????set?
{?company?=?value;?}
????????}
????}

????簡歷類:

Code
//簡歷
????public?class?Resume?:?ICloneable

????
{
????????private?string?name;
????????private?string?sex;
????????private?string?age;

????????private?WorkExperience?work;

????????public?Resume(string?name)

????????
{
????????????this.name?=?name;
????????????work?=?new?WorkExperience();
????????}

????????//設置個人信息
????????public?void?SetPersonalInfo(string?sex,?string?age)

????????
{
????????????this.sex?=?sex;
????????????this.age?=?age;
????????}
????????//設置工作經歷
????????public?void?SetWorkExperience(string?workDate,?string?company)

????????
{
????????????work.WorkDate?=?workDate;
????????????work.Company?=?company;
????????}

????????//顯示
????????public?void?Display()

????????
{
????????????Console.WriteLine("{0}?{1}?{2}",?name,?sex,?age);
????????????Console.WriteLine("工作經歷:{0}?{1}",?work.WorkDate,?work.Company);
????????}

????????public?Object?Clone()

????????
{
????????????return?(Object)this.MemberwiseClone();
????????}

????}

????客戶端:
??????static?void?Main(string[]?args)

????????
{
????????????Resume?a?=?new?Resume("大鳥");
????????????a.SetPersonalInfo("男",?"29");
????????????a.SetWorkExperience("1998-2000",?"XX公司");

????????????Resume?b?=?(Resume)a.Clone();
????????????b.SetWorkExperience("1998-2006",?"YY企業");

????????????Resume?c?=?(Resume)a.Clone();
????????????c.SetPersonalInfo("男",?"24");
????????????c.SetWorkExperience("1998-2003",?"ZZ企業");

????????????a.Display();
????????????b.Display();
????????????c.Display();

????????????Console.Read();
????????}

???? 下面我們看運行結果:?
????大鳥男 29
????工作經歷 1998-2003 ZZ企業
????大鳥 29
????? 工作經歷 1998-2003 ZZ企業
????大鳥男 24
????? 工作經歷 1998-2003 ZZ企業
????由于MemberwiseClone()方法是淺表復制(克隆),對于值類型克隆沒有問題,對于引用類型對象,只復制了引用,對引用的對象還是指向了原來的對象,所以就會出現我給a、b、c三個引用設置‘工作經歷’,但卻同時看到三個引用都是最后一次設置,因為三個引用都指向了同一個對象。
????“淺復制”,被復制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用都仍然指向原來的對象。
????“深復制”,深復制把引用對象的變量指向復制過的對象,而不是原有的被引用的對象。
????下面來看深復制的實現:
???? 代碼結構圖:

????實現代碼:
????工作經驗類:
???//工作經歷
????public?class?WorkExperience?:?ICloneable

????
{
????????private?string?workDate;
????????public?string?WorkDate

????????
{

????????????get?
{?return?workDate;?}

????????????set?
{?workDate?=?value;?}
????????}
????????private?string?company;
????????public?string?Company

????????
{

????????????get?
{?return?company;?}

????????????set?
{?company?=?value;?}
????????}

????????public?Object?Clone()

????????
{
????????????return?(Object)this.MemberwiseClone();
????????}
????}

????簡歷類:

Code
?//簡歷
????public?class?Resume?:?ICloneable

????
{
????????private?string?name;
????????private?string?sex;
????????private?string?age;

????????private?WorkExperience?work;

????????public?Resume(string?name)

????????
{
????????????this.name?=?name;
????????????work?=?new?WorkExperience();
????????}

????????private?Resume(WorkExperience?work)

????????
{
????????????this.work?=?(WorkExperience)work.Clone();
????????}

????????//設置個人信息
????????public?void?SetPersonalInfo(string?sex,?string?age)

????????
{
????????????this.sex?=?sex;
????????????this.age?=?age;
????????}
????????//設置工作經歷
????????public?void?SetWorkExperience(string?workDate,?string?company)

????????
{
????????????work.WorkDate?=?workDate;
????????????work.Company?=?company;
????????}

????????//顯示
????????public?void?Display()

????????
{
????????????Console.WriteLine("{0}?{1}?{2}",?name,?sex,?age);
????????????Console.WriteLine("工作經歷:{0}?{1}",?work.WorkDate,?work.Company);
????????}

????????public?Object?Clone()

????????
{
????????????Resume?obj?=?new?Resume(this.work);

????????????obj.name?=?this.name;
????????????obj.sex?=?this.sex;
????????????obj.age?=?this.age;


????????????return?obj;
????????}

????}

????客戶端代碼與上面相同,執行結果:
????大鳥男 29
????工作經歷 1998-2000 XX公司
????大鳥 29
????工作經歷 1998-2006 YY企業
????大鳥男 24
????工作經歷 1998-2003 ZZ企業
????3. 總結
????優缺點:
????使用原型模式有以下優點:
????(1)。在運行時增加或刪除產品,只要通過客戶端注冊原型實例即可將新產品類型增加到系統中,例如組態軟件中工具箱中的每個工具可以對應一個注冊的原型對象,可以通過增加原型對象擴展工具箱。
????(2)。很容易的創建復雜的對象:在圖像編輯和組態等軟件中,經常需要創建復雜的圖元,這些圖元是由簡單的圖元組成的,采用原型模式可以很容易的將復雜圖元作為一般圖元來使用,是軟件的工具箱具有擴展功能。
????(3)。減少工廠的層次:由于在.NET中可以使用反射工廠,因此這個優勢并不明顯。
????使用原型模式的缺點:是在有些情況下克隆功能不容易實現,特別是在遇到對象的循環引用時。
????在.NET中的很多類支持原型模式,例如我們希望獲得一個與現有數據集(DataSet)結構相同的數據集,既可以采用克隆的方法。注意,DataSet有Clone()和Copy()兩個方法,Clone()方法用來復制DataSet的結構,但不復制DataSet的數據,實現了原型模式的淺復制,Copy()方法,不但復制結構,也復制數據,實現了原型模式的深復制。