zoukankan      html  css  js  c++  java
  • 原型模式(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("
    Name:{0},Address{1}", p1.Name, p1.Address.ToString());
    			Console.Write("
    Name:{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操作数据库,则可先根据原型创建一对象作为修改前值(如果从数据库中查找两次比较耗时)。

  • 相关阅读:
    每天学一点管理知识——100-1=0定律
    每天学一点管理知识——赫勒法则
    每天学一点管理知识——卡贝定律
    每天学一点管理知识——韦特莱法则
    每天学一点管理知识——【证人的记忆】
    开发平台的优势在哪?
    WF工作流与管理类应用系统工作流需求实现的一些误区
    命名空间
    函数
    删除补充/集合/深浅拷贝
  • 原文地址:https://www.cnblogs.com/LoveTomato/p/8352654.html
Copyright © 2011-2022 走看看