原型模式
原型模式就是从一个对象再创建另一个可定制的对象,而不需要知道任何创建的细节。
原型模式本身是比较简单的,不过其中牵涉到浅复制和深复制的实现,下面使用.Net自带的方法和接口分别实现浅复制和深复制:
public class WorkExperience : ICloneable { public string workDate; public string experience; #region ICloneable 成员 public object Clone() { //浅复制 return this.MemberwiseClone(); } #endregion }
MemberwiseClone方法实现的是浅复制,即如果字段是值类型,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象,因此,原是对象及其复本引用的是同一对象。不过,经过测试发现,对string类型的执行的复制与值类型是相同的,修改新变量中string的值不会影响原变量的值测试如下:
WorkExperience we = new WorkExperience(); we.workDate="today"; we.experience="test";
//输出为work experience: today, test Console.WriteLine("work experience: {0},{1}", we.workDate, e.experience); WorkExperience we2 = (WorkExperience)we.Clone(); we2.experience = "test2"; we2.workDate = "tomorrow";
//输出为work experience: tomorrow,test2 Console.WriteLine("work experience: {0},{1}", we2.workDate, e2.experience);
//输出为work experience: today, test
Console.WriteLine("work experience: {0},{1}", we.workDate, we.experience);
下面演示如何进行深复制和浅复制:
public class Resume : ICloneable { public string name;
//引用类型,需要区分深复制和浅复制 public WorkExperience workExperience; public Resume(string name) { this.name = name; workExperience = new WorkExperience(); } public void SetExperience(string workDate, string experience) { workExperience.workDate=workDate; workExperience.experience=experience; } public void Show() { Console.WriteLine("name : {0}",name); Console.WriteLine("work experience: {0},{1}",workExperience.workDate,workExperience.experience); } /// <summary> /// 提供一个私有构造函数,供复制方法使用,以便复制WorkExperience的数据 /// </summary> /// <param name="workExperience"></param> private Resume(WorkExperience workExperience) { this.workExperience = (WorkExperience)workExperience.Clone(); } #region ICloneable 成员 /// <summary> ///深复制,实例化一个新的对象 /// </summary> /// <returns></returns> public object Clone() { Resume newResume = new Resume(this.workExperience); newResume.name = this.name; return newResume; } /// <summary> /// 浅复制 /// </summary> /// <returns></returns> public object Copy() { return this.MemberwiseClone(); } #endregion }
上例中Clone和Copy分别实现了深复制和浅复制,测试如下:
Resume myResume = new Resume("Kelly");
myResume.SetExperience("2004-2008", "University");
myResume.Show();
//使用浅复制,更改WorkExperience,则被复制对象也被更改
Resume newResume = (Resume)myResume.Copy();
newResume.SetExperience("2008-2012", "Master Degree");
newResume.name = "Mike";
myResume.Show();
//使用深复制,更改WorkExperience,被复制对象不会被更改
Resume newResume2 = (Resume)myResume.Clone();
newResume2.SetExperience("2012-now", "Company");
newResume2.name = "Jack";
myResume.Show();
运行结果为:
name : Kelly
work experience: 2004-2008,University
name : Kelly
work experience: 2008-2012,Master Degree
name : Kelly
work experience: 2008-2012,Master Degree
可以看出,name由于是string类型,所以始终不会被修改,work experience是引用类型,在第一次做浅复制后被修改,第二次做深复制后没有被修改。
一般在初始化信息不发生变化的情况下,克隆是最好的办法,这即隐藏了对象创建的细节,又对性能有很大的提高。