原型模式的定义是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。举个例子,我们有一个复杂对象,它内部有很多属性,它的构建过程也可能比较复杂。但是我们有一个场景,我们需要很多个这种对象来进行实验,我们可能需要观察它的某个属性的差异对实验结果的影响,那么我们怎么去实例化这些对象呢。传统的方式使用new来实例化,但是这样会非常麻烦,这个时候我们就可以使用原型模式。
我们先将该对象实例化一个实例出来。按照原型模式的定义,用原型实例指定创建对象的种类,然后拷贝这个对象。那么我们就将这个实例化出来的对象作为原型,然后我们通过拷贝这个原型来获得多个实例,之后我们只需要修改其中有差异的地方就可以了,这样就大大简化了我们实例化的过程。原型模式的结构图如下:
可以看到Prototype是一个原型,我们在需要对象的时候可以直接使用它的clone()方式来克隆一个实例。所以可以看出原型模式的核心就是实现实例的克隆,在C#中我们只需要实现一个ICloneable接口就可以达到我们的目的。
例如我们有一个简历对象
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(); } }
它里面包含了基本信息和工作经历,工作经历的定义如下
class WorkExperience { public string WorkDate { get; set; } public string Company { get; set; } }
按照原型模式的说法,我们就应该可以创建实例了
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(); }
那么输出结果是什么呢
是的,很奇怪,他们三个的工作经历都是一样的,并且都是最后设置的值。这个时候我们将他们各自工作经历的hashcode打出来
public void Display() { Console.WriteLine("{0} {1} {2} ", name, sex, age); Console.WriteLine("工作经历:{0} {1} HashCode:{2}", work.WorkDate, work.Company, work.GetHashCode()); }
那么这个时候显示的结果是什么呢
是的,他们的HashCode都是一样的,这说明在克隆的时候其实我们只是克隆它的引用,并没有将这个实际对象克隆,所以我们在修改克隆后对象时也会影响到原来的对象,这是原型模式需要特别注意的地方。知道了原因,那么我们就就它进行修改,我们的工作经历也要实现ICloneable接口
class WorkExperience : ICloneable { public string WorkDate { get; set; } public string Company { get; set; } public Object Clone() { return (Object)this.MemberwiseClone(); } }
然后我们也需要显示的调用一下工作经历的克隆方法来确保我们克隆不是它的引用
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() { Resume obj = (Resume)this.MemberwiseClone(); obj.work = (WorkExperience)work.Clone(); // 需要调用进行克隆 return obj; } }
这个时候它的结果就是正常的了
几句官方的话,它主要适用于
原文:https://www.cnblogs.com/aohost/p/12933917.html