1. 程式人生 > >原型模式(Prototype)

原型模式(Prototype)

on() 原型對象 orm obj 如何 取數據 .com 遞歸 從數據

模式定義

原型模式是一種創建型設計模式,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)