一般说要复制对象,不知道大家怎么做,我的 第一个想法是,实例化一个新的对象,不过这不是最优的做法。
其实,我所要说的是一种模式----原型模式。
“原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节”。也许上边这个图你看不懂,对我也看不懂,所以不做解释了,具体咱们看一个示例:
原型类:
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,我们看看运行效果