原型模式(Prototype Pattern)

来源:https://www.cnblogs.com/ygsworld/archive/2019/04/20/10741291.html
-Advertisement-
Play Games

原型模式概述 定義:使用原型實例指定待創建對象的類型,並且通過複製這個原型來創建新的對象。簡單的來說就是克隆(Clone),通過已經存在的,將其複製而產生新的。原型模式屬於創建型模式,將一個原型對象傳給要發動創建的對象(客戶端對象),該對象通過請求原型對象複製自己來實現創建過程。 既然是通過Clon ...


  • 原型模式概述

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

既然是通過Clone創建的,那麼就會存該拷貝是淺拷貝還是深拷貝的問題了。

淺拷貝(Shallow Clone):當原型對象被覆制時,只複製它本身和其中包含的值類型的成員變數,而引用類型的成員變數並沒沒複製。如我想將A複製一份出來,命名為為B,那麼我在淺拷貝後,確實可以得到A和B。而且A和B的值也相等,但是,我將B的值稍作修改,A的值也會變動,這往往不是我們想要的。因為我們想拷貝一個副本出來,二者也能獨立,這樣才算拷貝。但是,淺拷貝後A和B卻是指向同一片地址空間,也就是二者共用一個值,改一個,兩個都變。

深拷貝(Deep Clone):除了對象本身被覆制外,對象所包含的所有成員變數也被覆制,就是我們想要的那種拷貝,即有一個副本,與原者老死不想往來,互不影響

 原型模式的實現 :


 

結構:

  1. Prototype(抽象原型類):聲明克隆方法的介面,所有具體原型類的公共父類,抽象類、介面皆可,也可是具體類
  2. ConcretePrototpye(具體原型類):實現在抽象原型類中聲明的克隆方法,返回自己的克隆對象
  3. Client(客戶類):讓一個原型對象克隆自身而創建一個新的對象,直接實例化或通過工廠方法創建一個原型對象,在調用克隆方法即可

  • 原型模式應用實例

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

結構:

  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

運行結果:

上述FileStream類和BinaryFormatter類是實現對象序列化和反序列化的操作的,就是用序列化把當前對象寫入流中,流入文件,再用反序列化從文件中流出對象。文件相當於中介,當然,中介還可以是記憶體、網路

  • 原型管理器

 簡單介紹:原型管理器(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. 需要避免使用分層次的工廠類來創建分層次的對象,並且類的實例對象只有一個或很少的幾個組合狀態,通過複製原型對象得到新實例可能比使用構造函數創建一個新實例更方便

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • **Git安裝以及常用命令** 1、下載安裝Git,傻瓜式安裝相信大家都會。 官網下載地址:[https://git-scm.com/downloads] 2、Git基本操作 (1)git --version(查看git版本) (2)git --help(輔助命令查看) (3) git config ...
  • 通過這張圖我們很明顯就可以看出了區別: 普通函數調用的時候this的指向是window 而構造函數調用的時候this的指向是這個對象 列印結果是:凡塵 18 為什麼會是一個false呢???如果你聽過凡塵老師講課的話,在ES6的一張說過一道面試題。 創建構造函數的時候js執行了那些操作? 1、在記憶體 ...
  • 一、Express框架 1.1基本使用 創建http伺服器特別麻煩,express框架解決了這個的問題。 Express在node界的地位,就相當於jQuery在DOM界的地位。jQuery的核心就是“批量”,1個jQuery對象中可以封裝多個原生對象。Express的核心就是中間件,Express ...
  • 介紹 Vue.js + Nuxt.js 項目中如何使用、自定義錯誤信息、自定義規則 Vee-validate 校驗表單 ...
  • 在寫單文件組件時,一般都是把標簽、腳本、樣式寫到一起,這樣寫個人感覺有點不夠簡潔,所以就想著把樣式分離出去。 採用import載入樣式 在局部作用域(scoped)採用@import載入進來的樣式文件,想法是美好的。以為這樣載入進來的樣式文件也只對當前組件有效;可現實是殘酷的,這樣載入進來的樣式無法 ...
  • 一、路由機制(靜態資源文件處理) 1.1 Nodejs沒有根目錄 MIME類型:http://www.w3school.com.cn/media/media_mimeref.asp 在Apache中,它會自動將htdocs文件夾提供靜態化路由服務。 但是Nodejs沒有這個機制。 在文件夾中創建這樣 ...
  • 在單頁面應用程式(SPA)中,有些頁面的佈局結構是上下兩塊是固定,中間內容是變化的。這時在入口處固定上下部分就可以很好的解決這一問題。有少部分頁面沒有上下部分或不需要(如:用戶註冊、登陸頁面),針對這一情況怎麼解決 相容這兩種情況解決方案: App.vue 在入口處單個路由輸出 Frame.vue ...
  • 好處:方便了後端對HTTP請求中參數進行核驗,只需一次編寫效驗器,一行代碼便可對所有參數的pojo進行參數核驗!而且更改效驗邏輯時只需要更改效驗器類即可,實現瞭解耦合。 只需要程式員按照規範開發一個ParameterValidator類(如下圖1),將所有效驗方法寫在該類中即可在任意地方使用一行代碼 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...