一般說要復制對象,不知道大家怎么做,我的 第一個想法是,實例化一個新的對象,不過這不是最優的做法。
其實,我所要說的是一種模式----原型模式。
“原型模式其實就是從一個對象再創建另外一個可定制的對象,而且不需要知道任何創建的細節”。也許上邊這個圖你看不懂,對我也看不懂,所以不做解釋了,具體咱們看一個示例:
原型類:

abstract class Prototype { private String id; public Prototype(String id) { this.id = id; } public string Id { get { return id; } } public abstract Prototype Clone();//創ä¡ä建¡§一°?個?抽¨¦象¨®方¤?法¤¡§,ê?這a個?方¤?法¤¡§返¤¦Ì回?當Ì¡À前¡ã對?象¨®自Á?身¦¨ª } 具體原型類 class ConcretePrototypel : Prototype { public ConcretePrototypel(string id): base(id) { } public override Prototype Clone() { return (Prototype)this.MemberwiseClone(); } }
客戶端代碼

public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { ConcretePrototypel p1 = new ConcretePrototypel("I"); ConcretePrototypel c1 = (ConcretePrototypel)p1.Clone(); //從䨮對?象¨®p1開a始º?拷?貝À¡ä數ºy據Y Response.Write(c1.Id); Response.End(); } }
輸出結果就是一個 I
這樣就可以不用實例化 ConcretePrototypel(c1對象) 而是直接克隆對象p1
因為這種克隆非常常用,所以.net 在System命名空間中提供了ICloneable接口,其中就是唯一的一個方法Clone(),這樣只需要實現這個接口就可以完成原型模式了
我們來看看這個示例
定義一個簡歷類

public class Resume:ICloneable { public Resume() { // //TODO: 在¨²此ä?處ä|添¬¨ª加¨®構1造¨¬函¡¥數ºy邏?輯- // } 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 string Display() { return string.Format("{0} {1} {2},工¡è作Á¡Â經-歷¤¨²:êo{3} {4}", name, sex, age, timeArea ,company); } public object Clone() { return (object)this.MemberwiseClone(); } } 客戶端 protected void Page_Load(object sender, EventArgs e) { Resume a = new Resume("娟¨º兒¨´"); a.SetPersonalInfo("女?","25"); a.SetWorkExperience("1987-2012","xzx公?司?"); Resume b = (Resume)a.Clone(); b.SetWorkExperience("1998-2206","yy企¨®業°¦Ì"); Resume c = (Resume)a.Clone(); b.SetPersonalInfo("男D", "24"); Response.Write(a.Display()+"</br>"); Response.Write(b.Display() + "</br>"); Response.Write(c.Display() + "</br>"); }
運行結果:
這樣一來,客戶端的代碼清爽了許多,程序效率也高了許多,不用每個對象都New一次了。
一般在初始化的信息不發生變化的情況下,克隆是最好的辦法。這既隱藏了對象創建的細節,又對性能是大大的提高了
他的實現原理是,不重新初始化,而是動態的獲取對象運行時的狀態
二、淺復制與深復制
MemberwiseClone()方法是這樣,如果字段是值類型的,則對該字段執行逐位復制,如果字段是引用類型,則復制引用但不復制引用對象;因此,原始對象及其復本引用同一對象。
就是說如果類中有對象是引用類型,那么引用的對象數據時不會被克隆的。
我們修改一下上邊簡歷類的代碼,創建一個工作經歷的類 WorkExperience

1 public class WorkExperience 2 { 3 public WorkExperience() 4 { 5 // 6 //TODO: 在¨²此ä?處ä|添¬¨ª加¨®構1造¨¬函¡¥數ºy邏?輯- 7 // 8 } 9 10 private String workDate; 11 public String WorkDate 12 { 13 get { return workDate; } 14 set { workDate = value; } 15 } 16 17 private String company; 18 public String Company 19 { 20 get { return company; } 21 set { company = value; } 22 } 23 } 24 25 26 修改簡歷類 27 28 public class NewResume : ICloneable 29 { 30 public NewResume() 31 { 32 // 33 //TODO: 在¨²此ä?處ä|添¬¨ª加¨®構1造¨¬函¡¥數ºy邏?輯- 34 // 35 } 36 37 private string name; 38 private string sex; 39 private string age; 40 41 42 private WorkExperience work; 43 44 public NewResume(string name) 45 { 46 this.name = name; 47 work = new WorkExperience(); //實º¦Ì例¤y化¡¥工¡è作Á¡Â經-歷¤¨² 48 } 49 50 //設¦¨¨置?個?人¨?信?息¡é 51 public void SetPersonalInfo(String sex, String age) 52 { 53 this.sex = sex; 54 this.age = age; 55 } 56 57 //設¦¨¨置?工¡è作Á¡Â經-歷¤¨² 58 public void SetWorkExperience(String workDate, String company) 59 { 60 work.WorkDate = workDate; 61 work.Company = company; 62 } 63 64 //顯?示º? 65 public string Display() 66 { 67 return string.Format("{0} {1} {2},工¡è作Á¡Â經-歷¤¨²:êo{3} {4}", name, sex, age, work.WorkDate,work.Company); 68 } 69 70 public object Clone() 71 { 72 return (object)this.MemberwiseClone(); 73 } 74 } 75 76 77 客戶端: 78 NewResume a = new NewResume("娟¨º兒¨´"); 79 a.SetPersonalInfo("女?","25"); 80 a.SetWorkExperience("1987-2012","xzx公?司?"); 81 82 NewResume b = (NewResume)a.Clone(); 83 b.SetWorkExperience("1998-2206","yy企¨®業°¦Ì"); 84 85 NewResume c = (NewResume)a.Clone(); 86 b.SetPersonalInfo("男D", "24"); 87 88 Response.Write(a.Display()+"</br>"); 89 Response.Write(b.Display() + "</br>"); 90 Response.Write(c.Display() + "</br>");
運行結果
我們在來看先深復制
將NewResume類稍微修改一下,為其增加一個構造函數,並修改Clone()方法
構造函數:
public NewResume_01(WorkExperience work)
{
this.work = work; //實º¦Ì例¤y化¡¥工¡è作Á¡Â經-歷¤¨²
}
Clone() 方法
public object Clone()
{
NewResume_01 obj = new NewResume_01(this.work);
obj.name = name;
obj.sex = sex;
obj.age = age;
return obj;
}
修改一下WorkExperience(工作經歷類)類
為其增加一個方法,用於返回自身
public object Clone()
{
return this.MemberwiseClone();
}
ok,我們看看運行效果
文件下載路徑:http://files.cnblogs.com/netqq/Test.zip