設計模式-創建型-原型模式

来源:https://www.cnblogs.com/az4215/archive/2019/09/16/11525391.html
-Advertisement-
Play Games

引言: 原型模式是什麼?它是在什麼場景下被提出的呢?本章節,我們將詳細瞭解下原型模式。 在軟體系統中,當創建一個類的實例過程過於昂貴或複雜,並且我們需要創建多個這樣類的實例時,如果我們通過new來創建類實例,這就會增加創建類的複雜度和創建過程與客戶代碼複雜的耦合度。如果採用工廠模式來創建這樣的實例對 ...


引言:

  原型模式是什麼?它是在什麼場景下被提出的呢?本章節,我們將詳細瞭解下原型模式。

  在軟體系統中,當創建一個類的實例過程過於昂貴或複雜,並且我們需要創建多個這樣類的實例時,如果我們通過new來創建類實例,這就會增加創建類的複雜度和創建過程與客戶代碼複雜的耦合度。如果採用工廠模式來創建這樣的實例對象的話,隨著產品類的不斷增加,導致子類的數量不斷增多,也導致了相應工廠類的增加,維護的代碼維度增加了,因為有產品和工廠兩個維度了,反而增加了系統複雜程度,所以在這裡使用工廠模式來封裝類創建過程並不合適。由於每個類實例都是相同的(類型相同),但是每個實例的狀態參數會有不同,如果狀態數值也相同就沒意義了,有一個這樣的對象就可以了。當我們需要多個相同的類實例時,可以通過對原來對象拷貝一份來完成創建,這個思路正是原型模式的實現方式。

定義:

  原型模式就是通過給出一個原型對象來指明所要創建的對象類型,然後用複製這個對象的方法來創建更多的同類型對象。 

原型模式的兩種類型: 

  object類的clone方法只會拷貝對象中基本的數據類型,對於數組、容器對象、引用對象等都不會拷貝,這就是淺拷貝。如果要實現深拷貝,必須將原型模式中的數組、容器對象、引用對象等另行拷貝。 

 1 internal class Program
 2 {
 3     private static void Main(string[] args)
 4     {
 5         SunWukong sunwukong = new SunWukong()
 6         {
 7             Id = 1,
 8             Name = "孫悟空",
 9             Weapon = new Weapon()
10             {
11                 Name = "如意金箍棒"
12             }
13         };
14         SunWukong xingzhesun = (SunWukong)sunwukong.Clone();
15         Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
16         Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
17         Console.WriteLine("===============================");
18 
19         // 驗證克隆後屬性之間是否共用
20         xingzhesun.Id = 2;
21         xingzhesun.Name = "行者孫";
22         xingzhesun.Weapon.Name = "釘耙";
23         Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
24         Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
25         // 從結果可以看出,對於基本類型屬性,克隆之後不共用,而對於對象來說是共用的,這就是淺拷貝
26         Console.WriteLine("===============================");
27         Console.WriteLine($"孫悟空的武器{sunwukong.Weapon.GetHashCode()},行者孫的武器{sunwukong.Weapon.GetHashCode()}");
28         // 列印hashcode值可以看出,克隆後的實例與原型的Weapon指向同一個地址
29     }
30 }
31 
32 internal class SunWukong : ICloneable
33 {
34     public int Id { get; set; }
35     public string Name { get; set; }
36     public Weapon Weapon { get; set; }
37 
38     public object Clone()
39     {
40         return this.MemberwiseClone();
41     }
42 }
43 
44 internal class Weapon
45 {
46     public string Name { get; set; }
47 }
view code

 

  .net中提供了原型,即System命名空間下的介面ICloneable,只要實現該介面的Clone方法就可以之間原型拷貝。上述代碼中遺留了一個問題,如何實現深拷貝問題。 

 1 internal class Program
 2 {
 3     private static void Main(string[] args)
 4     {
 5         SunWukong sunwukong = new SunWukong()
 6         {
 7             Id = 1,
 8             Name = "孫悟空",
 9             Weapon = new Weapon()
10             {
11                 Name = "如意金箍棒"
12             }
13         };
14         SunWukong xingzhesun = (SunWukong)sunwukong.Clone();
15         // 引用類型再進行拷貝
16         xingzhesun.Weapon = (Weapon)xingzhesun.Weapon.Clone();
17         Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
18         Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
19         Console.WriteLine("===============================");
20         xingzhesun.Id = 2;
21         xingzhesun.Name = "行者孫";
22         xingzhesun.Weapon.Name = "釘耙";
23         Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
24         Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
25         Console.WriteLine("===============================");
26         Console.WriteLine($"孫悟空的武器{sunwukong.Weapon.GetHashCode()},行者孫的武器{xingzhesun.Weapon.GetHashCode()}");
27     }
28 }
29 
30 internal class SunWukong : ICloneable
31 {
32     public int Id { get; set; }
33     public string Name { get; set; }
34     public Weapon Weapon { get; set; }
35 
36     public object Clone()
37     {
38         return this.MemberwiseClone();
39     }
40 }
41 
42 internal class Weapon : ICloneable
43 {
44     public string Name { get; set; }
45 
46     public object Clone()
47     {
48         return this.MemberwiseClone();
49     }
50 }
view code 

 

深拷貝:

  1、複製對象的基本數據類型的成員變數值。

  2、為所有引用類型的成員變數申請存儲空間,並複製每個引用數據類型成員變數所引用的對象,直到該對象可達的所有對象。也就是說,對象進行深拷貝要對整個對象進行拷貝。

  3、深拷貝實現方式1:重寫clone方法。

  4、深拷貝實現方式2:通過對象序列化。 

 1 //對象深拷貝
 2  public static T Copy<T>(T oldObject) where T : class,new()
 3  {
 4     T newOrder = new T();
 5     MemoryStream stream = new MemoryStream();
 6     BinaryFormatter bf = new BinaryFormatter();
 7     bf.Serialize(stream, oldObject);
 8     stream.Position = 0;
 9     newOrder = (bf.Deserialize(stream) as T);
10     return newOrder;
11 }
view code

原型模式的註意事項和細節:

  1、創建新的對象比較複雜時,可以利用原型模式簡化對象的創建過程,同時也能夠提高效率。

  2、不用重新初始化對象,而是動態地獲取對象運行時的狀態。

  3、如果原始對象發生變化(增加或減少屬性),其它克隆對象也會發生相應的變化,無需修改代碼。

  4、在實現深克隆的時候可能需要比較複雜的代碼。    

  5、使用原型模式複製不會調用類的構造方法。因為對象的複製是通過調用clone方法完成的,它直接在記憶體種複製數據,因此不會調用到類的構造方法。不但構造方法中的代碼不會執行,甚至連訪問許可權都對原型模式無效。單例模式中,我們通過私有化構造函數來實現單例模式,但clone方法直接無視構造方法的許可權,所以,單例模式與原型模式是衝突的。

原型模式的優點:

  1、原型模式向客戶隱藏了創建新實例的複雜性。

  2、原型模式允許動態增加或較少產品類。

  3、原型模式簡化了實例的創建結構,工廠方法模式需要有一個與產品類等級結構相同的等級結構,而原型模式不需要這樣。

  4、產品類不需要事先確定產品的等級結構,因為原型模式適用於任何的等級結構。

缺點:

  1、需要為每一個類配備一個克隆方法,這對全新的類來說不是很難,但對已有的類進行改造時,需要修改源碼,即違反了OCP原則

參考:https://www.cnblogs.com/zhili/p/PrototypePattern.html

   https://yq.aliyun.com/articles/485574 


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

-Advertisement-
Play Games
更多相關文章
  • 1、JS的核心標準ECMAScript 組成 ECMAScript >核心語法標準 DOM >對文檔節點的操作 BOM >對瀏覽器的操作 2、JS的註釋: 單行註釋 //註釋內容 多行註釋 /* 註釋內容 */ 3、JS的保留字和關鍵字 關鍵字:有特殊功能的單詞如: break do try typ ...
  • 在寫pc端頁面時,用swiper插件發現在ie中用不了,百度下說是swiper從3以後向手機端發展,所以在pc端無響應。後來瞭解到,swiper3是專門針對移動端寫的。如果想相容IE8的話,應該引入swiper2. 也就是:idangerous.swiper.js 官網演示地址:http://2.s ...
  • 陰天,在不開燈的房間,當所有思緒都一點一點沉澱,愛情究竟是精神鴉片,還是世紀末的無聊消遣。 ...
  • 效果 效果圖如下,純css實現超酷炫的星級評分動畫效果 ​ ​ 實現思路 dom結構 用form實現 <form> <div class="star"> <input type="radio" id="rate5" name="rating" value="5"> <label for="rate5 ...
  • 效果 效果圖如下 ​ ​ 實現思路 dom結構 用兩個嵌套的div容器就可以了,父容器來控製圖標顯示的位置,子容器用來寫烏雲的樣式。而陰影和閃電的樣式都用偽元素就可以了,這些都是在css中定義的。 <div class="container"> <div class="stormy"></div> ...
  • 場景 Docker-Compose簡介與Ubuntu Server 上安裝Compose: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/100902301 在上面實現Compose成功安裝的基礎上,使用Compose啟動項目。 ...
  • Compose簡介 Compose是Docker官方的開源項目,負責對Docker容器集群的快速編排。 Compose是定義和運行多個Docker容器的應用。 舉例來說: 一個項目除了Tomcat容器外,還需要mysql服務容器,Compose允許用戶通過一個單獨的 docker-compose.y ...
  • 什麼是常量 用final修飾的成員變數表示常量,值一旦給定就無法改變! final修飾的變數有三種:靜態變數、實例變數和局部變數,分別表示三種類型的常量。 Class文件中的常量池 在Class文件結構中,最頭的4個位元組用於存儲魔數Magic Number,用於確定一個文件是否能被JVM接受,再接著 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...