码迷,mamicode.com
首页 > 其他好文 > 详细

原型模式(Prototype)

时间:2018-01-25 18:54:38      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:取数   tomato   根据   for   static   public   一个   深度   设计   

模式定义

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

UML类图

技术分享图片

  • 抽象原型
  • 具体原型
  • 客户端调用

    代码结构

    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除外)新建对象(实现复杂)
  2. 通过序列化与反序列化(实现简单)
    通过序列化深度复制对象,假设一人对象有名称和住址,住址为引用类型。

    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操作数据库,则可先根据原型创建一对象作为修改前值(如果从数据库中查找两次比较耗时)。

原型模式(Prototype)

标签:取数   tomato   根据   for   static   public   一个   深度   设计   

原文地址:https://www.cnblogs.com/LoveTomato/p/8352654.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!