標籤:tool mat str style each 客戶 targe row long
原型模式(Prototype)
定義:
原型模式:用原型執行個體指定建立對象的種類,並且通過複製這些原型建立新的對象。被複製的執行個體被稱為原型,這個原型是可定製的。
Prototype Pattern也是一種建立型模式,它關注的是大量相同或相似對象的建立問題。應用原型模式就是建立一個原型,然後通過對原型來進行複製的方法,來產生一個和原型相同或相似的新對象,或者說用原型執行個體指定建立對象的種類,並且通過複製這些原型建立新的對象。
模式中的角色
抽象原型類(Abstract Prototype):提供一個複製介面
具體原型類(Concrete Prototype): 實現了複製介面的具體原型類
原型模式的優點有:
-
- 原型模式向客戶隱藏了建立新執行個體的複雜性和具體的產品類,減少了客戶知道的名字的數目。
- 原型模式允通過註冊原型執行個體就可以將一個具體產品類併入到系統中,客戶可以在運行時刻建立和刪除原型。
- 減少了子類的構造。原型模式是Clone一個原型而不是請求Factory 方法建立一個,所以它不需要一個與具體產品類平行的Creator類層次。
- 產品類不需要事先確定產品的等級結構,因為原型模式適用於任何的等級結構。
- 原型模式具有給一個應用軟體動態載入新功能的能力。由於Prototype的獨立性較高,可以很容易動態載入新功能而不影響舊系統。
原型模式的缺點有:
原型模式的最重要缺點就是每一個類必須配備一個Clone方法,而且這個Clone方法需要對類的功能進行通盤考慮。這對全新的類來說不是很難,但對已有的類進行改造時,不一定是容易的事。
原型模式可以適用於以下情形:
-
- 類初始化需要消化非常多的資源,這個資源套件括資料、硬體資源等;
- 通過new產生一個對象需要非常繁瑣的資料準備或存取權限,則可以使用原型模式;
- 一個對象需要提供給其他對象訪問,而且各個調用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調用者使用;
- 當一個系統應該獨立於它的產品建立、構成和表示時;
- 當要執行個體化的類是在運行時刻指定時,例如通過動態裝載來建立一個類;
- 為了避免建立一個與產品類層次平行的工廠類層次時;
- 當一個類的執行個體只能有幾個不同狀態組合中的一種時。建立相應數目的原型並Clone它們可能比每次用合適的狀態手工執行個體化該類更方便一些。
淺拷貝與深拷貝
淺度複製(Shallow Copy):將原來對象中的所有欄位逐個複製到一個新對象,如果欄位是實值型別,則簡單地複製一個副本到新對象,改變新對象的實值型別欄位不會影響原對象;如果欄位是參考型別,則複製的是引用,改變目標對象中參考型別欄位的值將會影響原對象。
深度複製(Deep Copy):與淺複製不同之處在於對參考型別的處理,深複製將新對象中參考型別欄位指向複製過的新對象,改變新對象中引用的任何對象,不會影響到原來的對象中對應欄位的內容。
實值型別和參考型別的知識點可以瞭解:實值型別和參考型別深入理解
淺拷貝與深拷貝樣本:
拷貝對象School和Student:
[Serializable] public class Student : ICloneable { private string name = "xxx"; private int age = 0; public string Name { get { return name; } set { name = value; } } public int Age { get { return age; } set { age = value; } } /// <summary> /// 建立對象實現複製 /// </summary> /// <returns></returns> public Student NewClone() { return new Student() { age = this.age, name = this.name }; } /// <summary> /// 實現ICloneable介面 /// </summary> /// <returns></returns> public object Clone() { return this.MemberwiseClone(); } } [Serializable] public class School : ICloneable { private string m_Name = "init"; private int m_Number = -1; private Student m_Student; public string Name { get { return m_Name; } set { m_Name = value; } } public int Number { get { return m_Number; } set { m_Number = value; } } public Student Student { get { return m_Student; } set { m_Student = value; } } /// <summary> /// 建立對象實現複製,如果屬性是參考型別,需要一層層new賦值,直到屬性是實值型別為止 /// </summary> /// <returns></returns> public School NewClone() { return new School() { m_Name = this.m_Name, m_Number = this.Number, Student = this.Student.NewClone() }; } /// <summary> /// 實現ICloneable介面 /// </summary> /// <returns></returns> public object Clone() { return this.MemberwiseClone(); } }
序列化拷貝和反射拷貝:
public static class HelperTools { /// <summary> /// 序列化深拷貝 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source"></param> /// <returns></returns> public static T SerializableClone<T>(T source) { if (!typeof(T).IsSerializable) { throw new ArgumentException("The type must be serializable.", source.GetType().ToString()); } if (Object.ReferenceEquals(source, null)) { return default(T); } IFormatter formatter = new BinaryFormatter(); using (MemoryStream ms = new MemoryStream()) { formatter.Serialize(ms, source); ms.Seek(0, SeekOrigin.Begin); return (T)formatter.Deserialize(ms); } } /// <summary> /// 反射屬性淺拷貝 /// </summary> /// <param name="t"></param> /// <returns></returns> public static T PropertyClone<T>(T t) { if (Object.ReferenceEquals(t, null)) { return default(T); } Type type = t.GetType(); PropertyInfo[] propertyInfos = type.GetProperties(); Object obj = Activator.CreateInstance<T>(); Object p = type.InvokeMember("", BindingFlags.CreateInstance, null, t, null); foreach (PropertyInfo propertyInfo in propertyInfos) { if (propertyInfo.CanWrite) { object value = propertyInfo.GetValue(t, null); propertyInfo.SetValue(obj, value, null); } } return (T)obj; } }
public class Program { static void Main(string[] args) { School school = new School() { Name = "德源小學", Number = 0, Student = new Student() { Name = "兔基斯", Age = 18 } }; Console.WriteLine("************************原始值*****************************"); ShowSchoolInfo(school); Console.WriteLine("************************序列化深拷貝*****************************"); School serSchool = HelperTools.SerializableClone(school); serSchool.Name = "序列化"; serSchool.Number = 1; serSchool.Student.Name = "xuliehua"; serSchool.Student.Age = 20; ShowSchoolInfo(serSchool); ShowSchoolInfo(school); Console.WriteLine("************************建立對象深拷貝****************************"); School newSchool = (School)school.NewClone(); newSchool.Name = "new對象"; newSchool.Number = 2; newSchool.Student.Name = "newObject"; newSchool.Student.Age = 22; ShowSchoolInfo(newSchool); ShowSchoolInfo(school); Console.WriteLine("************************屬性反射淺拷貝*****************************"); School proSchool = HelperTools.PropertyClone(school); proSchool.Name = "反射"; proSchool.Number = 3; proSchool.Student.Name = "fanshe"; proSchool.Student.Age = 21; ShowSchoolInfo(proSchool); ShowSchoolInfo(school); Console.WriteLine("************************複製介面淺拷貝*****************************"); School cloneSchool = (School)school.Clone(); cloneSchool.Name = "複製"; cloneSchool.Number = 4; cloneSchool.Student.Name = "kelong"; cloneSchool.Student.Age = 23; ShowSchoolInfo(cloneSchool); ShowSchoolInfo(school); Console.ReadLine(); } public static void ShowSchoolInfo(School school) { Console.WriteLine("學校名:{0}, 學校編號:{1}, 學生名字:{2}, 學生年齡:{3}", school.Name, school.Number, school.Student.Name, school.Student.Age); } }
、
註:實現複製方法必須繼承ICloneable介面,序列化的類必須標明特性[Serializable]
總結:
原型設計模式總算告一段落,從原型設計模式出發,深拷貝、淺拷貝,參考型別、實值型別,拷貝方式,再回到起點原始設計模式,這一趟收穫頗多。
C#設計模式:原型模式(Prototype)及深拷貝、淺拷貝