原型模式(Prototype)
类图
描述
原型模式:
提供一个克隆自身的接口--Clone方法。
应用场景
定义一个学生类,包含一个值类型(int)的Age属性、两个引用类型Name(string)和Course属性。
public class Course { public string Name { get; set; } } public class Student : ICloneable { public string Name { get; set; } public int Age { get; set; } public Course Course { get; set; } public object Clone() { return this.MemberwiseClone(); } } static void Main(string[] args) { string value = ConfigurationManager.AppSettings["prototypePattern"]; Student student = (Student)Assembly.Load(value.Substring(0, value.IndexOf(‘.‘))).CreateInstance(value); student.Name = "Jim"; student.Age = 20; student.Course = new Course() { Name = "C++" }; Console.WriteLine("student:" + student.Name + "\t" + student.Age + "\t" + student.Course.Name); Console.WriteLine(); Student student1 = (Student)student.Clone(); student1.Name = "Tom"; student1.Age = 21; student1.Course.Name = "C#"; Console.WriteLine("student:" + student.Name + "\t" + student.Age + "\t" + student.Course.Name); Console.WriteLine("student1:" + student1.Name + "\t" + student1.Age + "\t" + student1.Course.Name); Console.WriteLine(); student1.Course.Name = "Java"; Console.WriteLine("student:" + student.Name + "\t" + student.Age + "\t" + student.Course.Name); Console.WriteLine("student1:" + student1.Name + "\t" + student1.Age + "\t" + student1.Course.Name); }
输出:
student:Jim 20 C++
student:Jim 20 C#
student1:Tom 21 C#
student:Jim 20 Java
student1:Tom 21 Java
从打印的结果可以看出,给原对象student拷贝一个新的student1对象并给student1属性赋值之后,原对象student的Age和Name没变,CourseName却变了。原因是拷贝之后,student把student1的Age和Name复制了一份,而student1的Course依然指向student的Course地址,所以,当student1的CourseName改变时,student的CourseName也随之改变,这就是浅拷贝。
但是在实际应用中,往往不希望发生这样的事情,也就是不能因为拷贝对象发生变化而影响到原对象。原因很简单,不能因为Tom选了C#这门课就要求Jim也必须把已经选的C++这门课改成C#。要解决这个问题,就需要拷贝一个全新的对象,即深拷贝。
下面把Student类和Course类小改一下,通过序列化和反序列化来创建一个全新的student:
[Serializable] public class Course { public string Name { get; set; } } [Serializable] public class Student : ICloneable { public string Name { get; set; } public int Age { get; set; } public Course Course { get; set; } public object Clone() { using (Stream objectStream = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); formatter.Serialize(objectStream, this); objectStream.Seek(0, SeekOrigin.Begin); return formatter.Deserialize(objectStream); } } }
输出:
student:Jim 20 C++
student:Jim 20 C++
student1:Tom 21 C#
student:Jim 20 C++
student1:Tom 21 Java
浅拷贝和深拷贝的区别:
浅拷贝:对值类型和string类型直接拷贝,对引用类型共用同一个指针;两个对象之间存在耦合;
深拷贝:给对象拷贝一个全新的对象,两个对象之间的耦合度为0。