我的設計模式之旅、12 原型模式

来源:https://www.cnblogs.com/linxiaoxu/archive/2022/09/19/16706400.html
-Advertisement-
Play Games

我的設計模式之旅,本節學習原型模式。從複製原有對象出現的兩大問題思考原型模式存在的必要性。探討原型模式的實現方法。 ...


編程旅途是漫長遙遠的,在不同時刻有不同的感悟,本文會一直更新下去。

思考總結

思考問題

如果沒有原型模式,當我們複製複雜對象,在新建相同類的對象,遍歷原始對象中的所有成員變數並將成員變數複製到新對象的過程中會產生什麼問題

  • 並非所有對象都能通過這種方式複製,因為對象可能擁有私有成員變數,它們在對象本身以外是不可見的。

  • 因為你必須知道對象所屬的類才能創建複製品,所以代碼必須依賴該類。有時你只知道對象所實現的介面,而不知道其所屬的具體類,比如可向方法的某個參數傳入實現了某個介面的任何對象。

什麼是原型模式

原型是一種創建型設計模式,使你能夠複製已有對象,而又無需使代碼依賴它們所屬的類。

原型模式:用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。

image-20220919002703390

含義:

  • 原型模式將克隆過程委派給被克隆的實際對象。模式為所有支持克隆的對象聲明瞭一個通用介面,該介面讓你能夠克隆對象,同時又無需將代碼和對象所屬類耦合。你甚至可以複製私有成員變數,因為絕大部分編程語言都允許對象訪問其自身的私有成員變數。支持克隆的對象即為原型

何時使用:

  • 如果你需要複製一些對象,同時又希望代碼獨立於這些對象所屬的具體類,可以使用原型模式。通常出現在代碼需要處理第三方代碼通過介面傳遞過來的對象時。即使不考慮代碼耦合的情況,你的代碼也不能依賴這些對象所屬的具體類,因為你不知道它們的具體 信息。
  • 如果子類的區別僅在於其對象的初始化方式,那麼你可以使用該模式來減少子類的數量。別人創建這些子類的目的可能 是為了創建特定類型的對象。
  • 當要實例化的類是在運行時刻指定時,例如,通過動態裝載。
  • 當一個類的實例只能有幾個不同狀態組合中的一種時。建立一系列預生成的、各種類型的對象作為原型並克隆它們可能比每次用合適的狀態手工實例化該類更方便一些。
    • 當你的對象有幾十個成員變數和幾百種類型時,對其進行克隆甚至可以代替子類的構造。創建一系列不同類型的對象並用不同的方式對其進行配置。如果所需對象與預先配置的對象相同,那麼你只需克隆原型即可,無需新建一個對象。

實現方法:

  • 創建原型介面,併在其中聲明克隆方法。如果你已有類層次結構,則只需在其所有類中添加該方法即可。
  • 原型類必須另行定義一個以該類對象為參數的構造函數。構造函數必須複製參數對象中的所有成員變數值到新建實體中。 如果你需要修改子類,則必須調用父類構造函數,讓父類複製其私有成員變數值。
  • 每個類都必須顯式重寫克隆方法並使 用自身類名調用 new 運算符。
  • 你還可以創建一個中心化原型註冊表,用於存儲常用原型。
    • 你可以新建一個工廠類來實現註冊表,或者在原型基類中添加一個獲取原型的靜態方法。該方法必須能夠根據客戶端代 碼設定的條件進行搜索。搜索條件可以是簡單的字元串,或 者是一組複雜的搜索參數。找到合適的原型後,註冊表應對原型進行克隆,並將複製生成的對象返回給客戶端。最後還要將對子類構造函數的直接調用替換為對原型註冊表工廠方法的調用。

應用實例:

  • 細胞分裂

優點:

  • 你可以克隆對象,而無需與它們所屬的具體類相耦合。
  • 你可以克隆預生成原型,避免反覆運行初始化代碼。性能提高。 逃避構造函數的約束。
  • 你可以更方便地生成複雜對象。
  • 你可以用繼承以外的方式來處理複雜對象的不同配置。

缺點:

  • 克隆包含迴圈引用的複雜對象可能會非常麻煩。
  • 必須實現 Cloneable 介面。

使用場景:

  • 資源優化場景。 類初始化需要消化非常多的資源,這個資源包括數據、硬體資源等。 性能和安全要求的場景。
  • 通過 new 產生一個對象需要非常繁瑣的數據準備或訪問許可權,則可以使用原型模式。
  • 一個對象多個修改者的場景。 一個對象需要提供給其他對象訪問,而且各個調用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調用者使用。
  • 在實際項目中,原型模式很少單獨出現,一般是和工廠方法模式一起出現,通過 clone 的方法創建一個對象,然後由工廠方法提供給調用者。

與其他模式的關係:

  • 原型可用於保存命令的歷史記錄。
  • 大量使用組合和裝飾的設計通常可從對於原型的使用中獲益。 你可以通過該模式來複制複雜結構,而非從零開始重新構造。
  • 原型並不基於繼承,因此沒有繼承的缺點。另一方面,原型需要對被覆制對象進行複雜的初始化。 工廠方法基於繼承, 但是它不需要初始化步驟。
  • 有時候原型可以作為備忘錄的一個簡化版本,其條件是你需要在歷史記錄中存儲的對象的狀態比較簡單,不需要鏈接其 他外部資源,或者鏈接可以方便地重建。
  • 抽象工廠、生成器和原型都可以用單例來實現。

註意事項:原型模式分淺拷貝和深拷貝,在設計原型模式的時候需要著重考慮。

參考資料

  • 《Go語言核心編程》李文塔
  • 《Go語言高級編程》柴樹彬、曹春輝
  • 《大話設計模式》程傑
  • 《深入設計模式》亞歷山大·什韋茨
  • 菜鳥教程

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

-Advertisement-
Play Games
更多相關文章
  • By:授客 QQ:1033553122 刪除表數據操作 清空所有表記錄 TRUNCATE TABLE your_table_name; 或者批量刪除滿足條件的表記錄 BEGIN LOOP DELETE FROM your_table_name WHERE rownum <= 50000; EXIT ...
  • 成本核算程式執行某個存儲過程一直阻塞,排查發現類似以下語句阻塞: select tbl1.product_id,sum(isnull(tbl1.qty,0) * isnull(tbl2.unit_other_cost,0)) as other_cost from tbl1.p_id=@pId and ...
  • MySQL的通用日誌: 用來記錄對資料庫的通用操作,包括錯誤的sql語句等信息。 通用日誌可以保存在:file(預設值)或 table(mysql.general_log表) mysql通用日誌的設置: general_log=ON|OFF 是否啟用通用日誌 general_log_file=HOS ...
  • 1 - 編程語言 1.1 編程 編程: 就是讓電腦為解決某個問題而使用某種程式設計語言編寫程式代碼,並最終得到結果的過程。 電腦程式: 就是電腦所執行的一系列的指令集合,而程式全部都是用我們所掌握的語言來編寫的,所以人們要控制電腦一定要通過電腦語言向電腦發出命令。 1.2 電腦語言 計 ...
  • 移動web開發之rem佈局 rem基礎 rem單位 rem (root em)是一個相對單位,類似於em,em是父元素字體大小。 不同的是rem的基準是相對於html元素的字體大小。 比如,根元素(html)設置font-size=12px; 非根元素設置width:2rem; 則換成px表示就是2 ...
  • 這個系列的目的是通過使用 JS 實現“乞丐版”的 React,讓讀者瞭解 React 的基本工作原理,體會 React 帶來的構建應用的優勢 1 HTML 構建靜態頁面 使用 HTML 和 CSS,我們很容易可以構建出上圖中的頁面 <!DOCTYPE html> <html lang="en"> < ...
  • 原型(prototype)是函數特有的屬性。只要創建了一個函數,這個函數就會自動創建一個prototype屬性(顯式原型),並指向該函數的原型對象。原型對象上都有一個constructor屬性,指向prototype屬性所在的函數(即函數本身)。而對於每一個構造函數創建出的實例對象,內部都會有一個[... ...
  • 移動端中的元素內容超出時,對容器設置overflow-x: auto就可以通過手勢水平移動。但是 PC 端只能通過滑鼠滾輪上下滑動,而不能水平移動。 只需要給元素添加一個監聽滑鼠滾輪事件,上下滑動時修改其 scrollLeft 屬性值就可以實現。直接貼上代碼: <div class="horizon ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...