一.介绍
原型模式(Prototype Pattern)。属于创建型模式。用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象。
二.实现
简单来说,原型模式可以直接复制一个现有的对象,而不需要重新new操作去创建。这种创建分两种方式,浅拷贝和深拷贝。
1.浅拷贝
定义一个接口IPerson来规范People。ICloneable是系统自带的接口,来定义需要用clone方法的。
public interface IPerson { object Clone(); } public class Person : IPerson, ICloneable { public string Name { get; set; } public Address Address { get; set; } public override string ToString() { var newLine = Environment.NewLine; var indent = " "; var str = $"Name:{Name}{newLine}Address:{newLine}{indent}Province:{Address.Province}{newLine}{indent}City:{Address.City}{newLine}"; return str; } /// <summary> /// 浅拷贝 /// </summary> /// <returns></returns> public object Clone() { return this.MemberwiseClone(); } } public class Address { public string City { get; set; } public string Province { get; set; } }
代码实现。
public static void Main(string[] args) { var person1 = new Person { Name = "aaa", Address = new Address { City = "Wuhan", Province = "HuBei" } }; Console.WriteLine("Person1 is "); Console.WriteLine(person1.ToString()); var person2 = person1.Clone() as Person; Console.WriteLine("Cloned Person2 is "); Console.WriteLine(person2.ToString()); Console.WriteLine("============= 修改原对象 ============="); person1.Name = "bbb"; person1.Address.Province = "Shanghai"; person1.Address.City = "shanghai"; Console.WriteLine("Person1 is"); Console.WriteLine(person1.ToString()); Console.WriteLine("Cloned Person2 is "); Console.WriteLine(person2.ToString()); Console.WriteLine("============= 修改复制对象 ============="); person2.Name = "ccc"; person2.Address.Province = "Guangdong"; person2.Address.City = "GuangZhou"; Console.WriteLine("Person1 is"); Console.WriteLine(person1.ToString()); Console.WriteLine("Cloned Person2 is "); Console.WriteLine(person2.ToString()); }
结果如图。
从结果可见,people修改了属性值,对people2的属性值没有影响。反过来,people2修改属性值对people也没有影响。但两者address的引用修改后,都互相影响。
2.深拷贝
public interface IPerson { object Clone(); } [Serializable] public class Person : IPerson, ICloneable { public string Name { get; set; } public Address Address { get; set; } public override string ToString() { var newLine = Environment.NewLine; var indent = " "; var str = $"Name:{Name}{newLine}Address:{newLine}{indent}Province:{Address.Province}{newLine}{indent}City:{Address.City}{newLine}"; return str; } /// <summary> /// 深拷贝 /// </summary> /// <returns></returns> public object Clone() { XmlSerializer serializer = new XmlSerializer(typeof(Person)); using (var stream = new System.IO.MemoryStream()) { serializer.Serialize(stream, this); stream.Seek(0, System.IO.SeekOrigin.Begin); return serializer.Deserialize(stream) as Person; } } } [Serializable] public class Address { public string City { get; set; } public string Province { get; set; } }
执行方法和上面一样,结果是属性值和引用值都不相互影响。通过序列化和反序列化创建了一个新的对象,这样拷贝出来的类指向就不会和原有的类一样。
三.总结
优点:
1.隐藏了创建实例的繁琐过程,只需要通过clone方法就能获取实例。
2.使用拷贝代替new,减少资源损耗。
缺点:
需要在每个需要拷贝的类中实现clone方法。