前进中的蜗牛

番茄大叔

水滴穿石,非一日之功;没有量变,何来质变。

原型模式(Prototype)

模式定义

原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

UML类图

  • 抽象原型 定义复制方法clone()方法
  • 具体原型 实现抽象原型中的复制方法 this.MemberwiseClone()
  • 客户端调用

代码结构

MemberwiseClone()方法是Object对象的浅复制的方法。

	public static class Client
	{
		public static void Run()
		{
			ConcretePrototype p = new ConcretePrototype("I");
			ConcretePrototype c = (ConcretePrototype)p.Clone();
			if(p != c)
			{
				Console.WriteLine("The Copy Object is not same.");
			}
			Console.WriteLine(c.Id);
		}
	}
 
	public abstract class Prototype
	{
		private string _id;

		public Prototype(string id)
		{
			this._id = id;
		}

		public string Id
		{
			get { return _id; }
		}

		public abstract Prototype Clone();
	}

	public class ConcretePrototype : Prototype
	{
		public ConcretePrototype(string id) : base(id)
		{
		}

		public override Prototype Clone()
		{
			return (Prototype)this.MemberwiseClone();
		}
	}

C#代码优化

其实没必要定义抽象原型对象,如那个类需要具有复制的功能,直接继承ICloneable接口就可以了

	public class ConcretePrototype : ICloneable
	{
		private string _id;
		public string Id
		{
			get { return _id; }
		}
		public ConcretePrototype(string id) 
		{
			this._id = id;
		}
		public object Clone()
		{
			return this.MemberwiseClone();
		}
	}

深度复制

以上谈论的类中不包含引用类型成员(string类型除外,因每次操作其实新建一个对象,可当作值类型处理)。如果包含引用成员,以上为浅复制(即引用成员被对象和复制对象公用)。这是有两种解决办法:

  1. 通过递归对象内引用成员(string除外)执行clone()(实现复杂)
  2. 通过序列化与反序列化(实现简单)
    通过序列化深度复制对象,假设一Person类对象有一Address类型属性,Address为引用类型。
public static class PrototypeClient
	{
		public static void Run()
		{
			Person p1 = new Person() { Name = "LoveTomato", Address = new Address("China", "BeiJing", "Haidian") };
			Person p2 = p1.Clone() as Person;
			p2.Address.Area = "Chaoyang";
			Console.Write("\nName:{0},Address{1}", p1.Name, p1.Address.ToString());
			Console.Write("\nName:{0},Address{1}", p2.Name, p2.Address.ToString());
		}
	}
	[Serializable]
	public class Person : ICloneable
	{
		public string Name { get; set; }

		public Address Address { get; set; }

		public object Clone()
		{
			BinaryFormatter bf = new BinaryFormatter();
			MemoryStream ms = new MemoryStream();
			bf.Serialize(ms, this);

			ms.Position = 0;
			return (bf.Deserialize(ms));
		}
	}

	[Serializable]
	public class Address
	{
		public string Country { get; set; }
		public string City { get; set; }
		public string Area { get; set; }
		public Address(string country, string city, string area)
		{
			this.Country = country;
			this.City = city;
			this.Area = area;
		}
		public override string ToString()
		{
			return string.Format("Country:{0},City:{1},Area:{2}", this.Country, this.City, this.Area);
		}
	}

情景模式

在新建一个对象花费代价比较大时(需要从数据库或远程获取数据等),可以使用原型法创建对象。
在对数据库中数据修改做日志时,要求记录修改前值与修改后值。因为项目通过ORM操作数据库,则可先根据原型创建一对象作为修改前值(如果从数据库中查找两次比较耗时)。

posted @ 2018-01-25 18:37  LoveTomato  阅读(208)  评论(0编辑  收藏  举报