原型模式(Prototype Pattern)

  • 原型模式概述

 定義:使用原型實例指定待建立對象的類型,而且經過複製這個原型來建立新的對象。簡單的來講就是克隆(Clone),經過已經存在的,將其複製而產生新的。原型模式屬於建立型模式,將一個原型對象傳給要發動建立的對象(客戶端對象),該對象經過請求原型對象複製本身來實現建立過程。網絡

既然是經過Clone建立的,那麼就會存該拷貝是淺拷貝仍是深拷貝的問題了。ide

淺拷貝(Shallow Clone):當原型對象被複制時,只複製它自己和其中包含的值類型的成員變量,而引用類型的成員變量並沒沒複製。如我想將A複製一份出來,命名爲爲B,那麼我在淺拷貝後,確實能夠獲得A和B。並且A和B的值也相等,可是,我將B的值稍做修改,A的值也會變更,這每每不是咱們想要的。由於咱們想拷貝一個副本出來,兩者也能獨立,這樣纔算拷貝。可是,淺拷貝後A和B倒是指向同一片地址空間,也就是兩者共用一個值,改一個,兩個都變。函數

深拷貝(Deep Clone):除了對象自己被複制外,對象所包含的全部成員變量也被複制,就是咱們想要的那種拷貝,即有一個副本,與原者老死不想往來,互不影響工具

 原型模式的實現 :this


 

結構:spa

  1. Prototype(抽象原型類):聲明克隆方法的接口,全部具體原型類的公共父類,抽象類、接口皆可,也但是具體類
  2. ConcretePrototpye(具體原型類):實如今抽象原型類中聲明的克隆方法,返回本身的克隆對象
  3. Client(客戶類):讓一個原型對象克隆自身而建立一個新的對象,直接實例化或經過工廠方法建立一個原型對象,在調用克隆方法便可

  • 原型模式應用實例

 問題描述:爲某銷售管理系統設計並實現一個客戶類Customer,在客戶類中包含一個名爲客戶地址的成員變量,客戶地址的類型爲Address,用淺克隆和深克隆分別實現Customer對象的複製,並比較這兩種克隆方式的異同(異同前面簡單說了,就不重複了)prototype

結構 :設計

 1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5 using System.Runtime.Serialization.Formatters.Binary; //序列化
 6 using System.IO;//文件
 7 using System.Runtime.Serialization;//序列化異常處理
 8 
 9 namespace Customer  10 {  11     [Serializable]//將Customer類設置爲可序列化
 12     public abstract class Customer : ICloneable  13  {  14         public abstract object Clone();  15  }  16 
 17     [Serializable]//將Address類設置爲可序列化
 18     public class Address//地址類
 19  {  20         private string province;  21         private string city;  22 
 23         public string City  24  {  25             get { return city; }  26             set { city = value; }  27  }  28 
 29         public string Province  30  {  31             get { return province; }  32             set { province = value; }  33  }  34 
 35         public  Address(string province,string city)  36  {  37             this.province = province;  38             this.city = city;  39  }  40 
 41         public override string ToString()//打印地區
 42  {  43             return "地址爲:" + province + " 省," + city + " 市。";  44  }  45  }  46 
 47     [Serializable]//將CustomerA設置爲可序列化
 48     public class CustomerA : Customer//顧客A類
 49  {  50         private string name;  51         private int age;  52         private string call;  53         private Address address;  54 
 55         public Address Address  56  {  57             get { return address; }  58             set { address = value; }  59  }  60 
 61         public string Name  62  {  63             get { return name; }  64             set { name = value; }  65  }  66        
 67         public int Age  68  {  69             get { return age; }  70             set { age = value; }  71  }  72         
 73         public string Call  74  {  75             get { return call; }  76             set { call = value; }  77  }  78 
 79         public CustomerA(string name, int age, string call,Address address)  80  {  81             this.name = name;  82             this.age = age;  83             this.call = call;  84             this.address = address;  85  }  86 
 87         public override string ToString()  88  {  89             return "客戶A--姓名:" + this.name + " 年齡:" + this.age + " 聯繫方式:" + this.call + " "+ this.address.ToString();  90  }  91 
 92        #region 淺克隆+this.MemberwiseClone()
 93        public  object MemClone()  94  {  95            return this.MemberwiseClone();  96  }  97        #endregion
 98 
 99        #region 深克隆+object Clone()
100        public override object Clone() 101  { 102            Kits.FileSer(@"d:\1.txt", this);// 103            object obj = Kits.FileDSer(@"d:\1.txt"); 104            return obj; 105  } 106        #endregion
107  } 108 
109     [Serializable]//將CustomerB設置爲可序列化
110     public class CustomerB : Customer//顧客B類
111  { 112         private string name; 113         private int age; 114         private string call; 115         private Address address; 116 
117         public Address Address 118  { 119             get { return address; } 120             set { address = value; } 121  } 122 
123         public string Name 124  { 125             get { return name; } 126             set { name = value; } 127  } 128 
129         public int Age 130  { 131             get { return age; } 132             set { age = value; } 133  } 134 
135         public string Call 136  { 137             get { return call; } 138             set { call = value; } 139  } 140 
141         public CustomerB(string name, int age, string call, Address address) 142  { 143             this.name = name; 144             this.age = age; 145             this.call = call; 146             this.address = address; 147  } 148 
149         public override string ToString() 150  { 151             return "客戶B--姓名:" + this.name + " 年齡:" + this.age + " 聯繫方式:" + this.call + " " + this.address.ToString(); 152  } 153 
154        #region 淺克隆+this.MemberwiseClone()
155        public  object MemClone() 156  { 157            return this.MemberwiseClone(); 158  } 159        #endregion
160 
161        #region 深克隆+object Clone()
162        public override object Clone() 163  { 164            Kits.FileSer(@"d:\1.txt", this);//
165            object obj = Kits.FileDSer(@"d:\1.txt");//
166            return obj; 167  } 168         #endregion
169  } 170     
171    public class Kits//工具類
172  { 173        public static void FileSer(string path,object obj)//讀出信息
174  { 175            FileStream fs = new FileStream(path, FileMode.OpenOrCreate);//通道 序列化
176            BinaryFormatter bf = new BinaryFormatter();//搬運工
177            try
178  { 179                bf.Serialize(fs, obj);//序列化
180  } 181            catch (SerializationException e) 182  { 183                Console.WriteLine("該文件進行序列化失敗。緣由 : " + e.Message); 184                throw; 185 
186  } 187            finally { fs.Close(); } 188  } 189 
190        public static object  FileDSer(string path)//寫入
191  { 192            FileStream fs = new FileStream(path, FileMode.Open);//通道、路徑,權限
193            BinaryFormatter bf = new BinaryFormatter();//搬運工
194            object obj = null; 195            try
196  { 197                obj=bf.Deserialize(fs);//反序列化
198  } 199            catch (SerializationException e) 200  { 201                Console.WriteLine("該文件進行反序列化失敗。緣由 : " + e.Message); 202                throw; 203 
204  } 205            finally 
206  { 207  fs.Close(); 208  } 209            return obj; 210  } 211  } 212 
213     class Program 214  { 215         static void Main(string[] args) 216  { 217             Console.WriteLine("\n--------------------------------Customer-------------------------------------"); 218             Address addr1 = new Address("中國江蘇", "揚州"); 219             CustomerA c1 = new CustomerA("社會人c1", 20, "13288888888", addr1); 220             Console.WriteLine(c1.ToString());//c1的做爲原對象
221 
222             Console.WriteLine("\n-----------------------------------Copy(c2 = c1)-------------------------------------"); 223             CustomerA c2 = c1; 224             Console.WriteLine("社會人c2,更新信息.直接複製對象\n"); 225  Console.WriteLine(); 226  Console.WriteLine(c2.ToString()); 227 
228             Console.WriteLine("\n-----------------------------ShallowCopy-------------------------------------"); 229  Console.WriteLine(); 230             Console.WriteLine("社會人c3,更新信息\n"); 231             CustomerA c3 = (CustomerA)c1.MemClone();//淺克隆
232  Console.WriteLine(c3.ToString()); 233 
234             Console.WriteLine("此時 c2:"); 235  Console.WriteLine(c2.ToString()); 236 
237             Console.WriteLine("\n--------------------------------Customer-------------------------------------\n"); 238  Console.WriteLine(); 239             Address addr2 = new Address("中國廣東", "廣州"); 240             CustomerB c4 = new CustomerB("小豬佩琪", 24, "16612345678", addr2); 241             Console.WriteLine("c4 "+c4.ToString()); 242             Console.WriteLine("\n--------------------------------DeepCopy(update c5.Age = 26)--------------------------\n"); 243 
244             CustomerB c5 = (CustomerB)c4.Clone(); 245             c5.Age = 26; 246             Console.WriteLine("一年後,搬家\n"); 247             c5.Address = new Address("中國天津", "河西區"); 248  Console.WriteLine(c5.ToString()); 249 
250             Console.WriteLine("此時 c4:"); 251  Console.WriteLine(c4.ToString()); 252  ; 253  } 254  } 255 }
View Code

運行結果:3d

上述FileStream類和BinaryFormatter類是實現對象序列化和反序列化的操做的,就是用序列化把當前對象寫入流中,流入文件,再用反序列化從文件中流出對象。文件至關於中介,固然,中介還能夠是內存、網絡code

  • 原型管理器

 簡單介紹:原型管理器(Prototype Manager)就是將多個原型對象存儲在一個集合中供客戶端使用,它是一個專門負責克隆對象的工廠,其中定義了一個集合用於存儲原型對象,若是須要某個原型對象的一個克隆,能夠經過複製集合中對應的原型對象得到。

 1 using System.Collections;  2 class PrototypeManager  3 {  4 Hashtable ht = new Hashtable();  //使用Hashtable存儲原型對象
 5     public PrototypeManager()  6  {  7         ht.Add("A", new ConcretePrototypeA());  8         ht.Add("B", new ConcretePrototypeB());  9  } 10     public void Add(string key, Prototype prototype) 11  { 12  ht.Add(key,prototype); 13  } 14     public Prototype Get(string key) 15  { 16         Prototype clone = null; 17         clone = ((Prototype)ht[key]).Clone();  //經過克隆方法建立新對象
18         return clone; 19  } 20 }
View Code 

原型模式的優缺點和適用環境


 

  • 原型模式的優勢:
  1. 簡化對象的建立過程,經過複製一個已有對象實例能夠提升新實例的建立效率
  2. 擴展性好
  3. 提供了簡化的建立結構,原型模式中的產品的複製是經過封裝在原型類中的克隆方法實現的,無需專門的工廠類來建立產品
  4. 能夠經過深克隆的方式保存對象的狀態,使用原型模式將對象複製一份並其狀態保存起來,以便在須要的時候使用,可輔助實現撤銷操做
  • 原型模式的缺點:
  1. 須要爲每個類準備一個克隆方法,並且該克隆方法位於一個類的內部,當對已有類進行改造時,須要修改原代碼,違背了開閉原則
  2. 在實現深克隆時須要寫較複雜的代碼,並且當對象之間存在多重的嵌套引用時,爲了實現深克隆,每一層對象對應的類必須支持深克隆,實現起來較煩較煩....
  • 原型模式的適用環境:
  1. 建立新對象成本較大,新對象能夠經過複製已有對象來得到,若是是類似對象,則能夠對其成員變量修改
  2. 系統要保存對象的狀態,而對象的狀態變化很小
  3. 須要避免使用分層次的工廠類來建立分層次的對象,而且類的實例對象只有一個或不多的幾個組合狀態,經過複製原型對象獲得新實例可能比使用構造函數建立一個新實例更方便
相關文章
相關標籤/搜索