軟體設計模式系列之七——原型模式

来源:https://www.cnblogs.com/coodream2009/archive/2023/09/17/17707672.html
-Advertisement-
Play Games

系統設計之緩存五種策略 當我們在架構中引入緩存時,緩存和資料庫之間的同步就變得不可避免。 讓我們看看如何保持數據同步的五種常見策略。 1)閱讀策略: 緩存在一邊 通讀2)寫策略:寫周圍 回信 寫通緩存策略經常組合使用。例如,write-around 通常與 cache-aside 一起使用,以確保緩 ...


1 模式的定義

原型模式(Prototype Pattern)是一種創建型設計模式,其主要目的是通過複製現有對象來創建新對象,而不是使用構造函數。原型模式將對象的創建委托給原型對象,通過克隆(複製)來生成新對象,這種方式可以避免對象的重覆初始化,提高性能,並使對象的創建更加靈活和動態。

原型模式的關鍵思想是通過複製已有對象的屬性和狀態來創建新的對象,這種方式避免了每次都使用構造函數初始化對象,特別適用於對象創建過程複雜、耗時或需要動態配置的情況。

2 舉例說明

原型模式在日常生活中的一個常見示例是使用複印機來複制文件或文檔。如果你需要複製一份文件,一般情況下不會手工重新編寫該文件的每個字,而是使用複印機來製作副本。在這裡,原文件充當原型,而複印機則是用於創建新文件副本的工具。使用複印機來複制文件,通過克隆原文件來創建新文件副本,從而節省時間和工作量。

還有一個例子就是在西游記中,孫悟空用自己的猴毛變成很多新的孫悟空,也可以看作孫悟空用自己做原型,拷貝出相同的猴子。

這些例子都有助於更好地理解原型模式的概念和應用。

3 結構

原型模式的結構包括以下要素:

抽象原型介面(Prototype):這是一個抽象介面或抽象類,它聲明瞭一個克隆方法(通常命名為 clone() 或類似的名稱)。這個方法用於複製當前對象並返回一個新的副本。所有具體原型類都必須實現這個介面或繼承這個抽象類,以確保它們能夠被克隆。

具體原型類(Concrete Prototype):這些是實際的對象類,它們實現了抽象原型介面,並提供了自己的克隆方法。具體原型類通常包含對象的屬性和方法。當客戶端需要創建新對象時,它們通過調用克隆方法來複制現有對象。

客戶端(Client):客戶端代碼是使用原型模式的地方,它通過調用具體原型類的克隆方法來創建新對象。客戶端不需要瞭解對象的具體構造方式,只需知道如何複製對象。

以下是原型模式的典型結構示意圖

在這個結構中,抽象原型介面定義了克隆方法,具體原型類實現了克隆方法,並可以包含其他屬性和方法。客戶端代碼通過克隆方法創建新對象,而不必關心對象的具體構造細節。這種結構使得對象的創建更加靈活和可維護。

4 實現步驟

實現原型模式的關鍵步驟包括以下幾個:

創建抽象原型介面(Prototype):首先,創建一個抽象原型介面或抽象類,其中包含一個克隆方法(通常命名為 clone() 或類似的名稱),用於複製當前對象並返回一個新的副本。這個介面將規範所有具體原型類必須實現的方法。

創建具體原型類(Concrete Prototype):對於每個需要被克隆的具體對象類型,創建一個具體原型類,它實現了抽象原型介面,並提供了自己的克隆方法。在克隆方法中,通常會創建一個新的對象,將當前對象的屬性值複製給新對象,並返回新對象。

客戶端使用原型對象:在客戶端代碼中,當需要創建新對象時,不直接使用構造函數,而是通過克隆已有的原型對象來創建新對象。客戶端代碼通常只需要知道如何調用原型對象的克隆方法,而無需瞭解對象的具體構造細節。

克隆方法的實現:在具體原型類中,克隆方法的具體實現取決於對象的類型和屬性。如果對象包含引用類型的成員變數,需要考慮深度克隆以確保對象的所有狀態都被正確複製。

測試和驗證:在客戶端代碼中測試原型模式,確保克隆的對象與原始對象在屬性和行為上一致。

5 代碼實現

以下是一個通用的原型模式實現步驟示例(使用Java):

// 1. 創建抽象原型介面
interface Prototype {
    Prototype clone();
}

// 2. 創建具體原型類
class ConcretePrototype implements Prototype {
    private String field;

    public ConcretePrototype(String field) {
        this.field = field;
    }

    @Override
    public Prototype clone() {
        return new ConcretePrototype(this.field);
    }

    public void setField(String field) {
        this.field = field;
    }

    public String getField() {
        return field;
    }
}

// 3. 客戶端使用原型對象
public class Client {
    public static void main(String[] args) {
        // 創建原型對象
        Prototype original = new ConcretePrototype("Original Field");

        // 克隆原型對象來創建新對象
        Prototype clone = original.clone();

        // 驗證新對象的屬性與原始對象相同
        System.out.println("Original Field: " + original.getField());
        System.out.println("Clone Field: " + clone.getField());
    }
}

在這個示例中,抽象原型介面定義了克隆方法,具體原型類實現了該介面並提供了自己的克隆方法。客戶端通過克隆方法創建新對象,驗證新對象的屬性與原始對象相同。這個示例展示了原型模式的基本實現步驟。

6 典型應用場景

原型模式在以下情況下是典型的應用場景:

需要創建對象的成本較高:當對象的創建和初始化成本較高時,原型模式可以顯著提高性能。每次都使用構造函數創建對象可能會導致不必要的開銷,因此通過複製已有對象來創建新對象更為高效。

在電腦游戲中,創建和初始化複雜的游戲角色可能需要大量時間和資源。如果游戲需要大量相似的角色,可以使用原型模式來複制現有角色,節省創建時間。

對象的屬性變化頻繁:當對象的屬性需要經常變化,但你希望保持對象的初始狀態作為基礎,可以使用原型模式。這樣,你可以創建一個原型對象,並根據需要克隆它來創建新的對象。

在圖形設計工具中,用戶可以創建和編輯圖形對象,如圖形文本框。原始對象可以充當原型,用戶可以複製它來創建多個類似但具有不同文本內容的圖形文本框。

動態配置對象:當對象的屬性需要根據運行時配置或用戶輸入而變化時,原型模式很有用。你可以創建一個原型對象,然後根據需要修改其屬性,而無需重新構建對象。

在網站創建工具中,用戶可以創建網頁並自定義顏色、字體、佈局等屬性。原始網頁對象可以作為原型,用戶可以克隆它並根據自己的需求修改屬性。

保護性拷貝:原型模式可以用於創建對象的深拷貝,以保護原始對象免受外部修改的影響。這對於涉及敏感數據或狀態的對象非常有用。

在安全敏感的應用程式中,用戶身份驗證對象可能包含用戶的敏感信息。通過使用原型模式創建深拷貝,可以確保不會在外部修改原始對象的敏感數據。

總之,原型模式適用於需要創建對象的成本高、屬性變化頻繁、動態配置或需要保護性拷貝的場景。它提供了一種高效、靈活和可維護的方式來創建對象,併在許多領域中有廣泛的應用。

7 優缺點

優點:
提高性能:避免了對象的重覆初始化,提高了對象創建的效率。

簡化對象創建:客戶端代碼可以通過克隆來創建新對象,無需瞭解對象的具體構造方式。

動態配置對象:允許在運行時動態配置對象的屬性。

保護性拷貝:可以創建對象的深拷貝,保護原始對象免受修改的影響。

缺點:
需要實現克隆方法:每個具體原型類都需要實現克隆方法,這可能需要一些額外的工作。

淺克隆問題:預設的克隆操作是淺克隆,如果對象包含引用類型的成員變數,可能需要手動實現深克隆。

8 類似模式

在 Spring 框架中,使用了原型模式和單例模式來管理對象的創建和生命周期。

原型模式在 Spring 中的應用:

原型範圍(Scope)的 Bean:在 Spring 中,你可以將一個 Bean 配置為原型範圍,這意味著每次從 Spring 容器請求該 Bean 時,都會創建一個新的實例。這就是原型模式的應用,每次都克隆一個對象來創建新實例。這對於那些需要頻繁創建新對象的場景非常有用,因為每個請求都會得到一個全新的 Bean 實例,而不會共用狀態。

使用 prototype 作用域聲明 Bean:在 Spring 的配置文件或使用註解時,你可以明確將 Bean 的作用域聲明為 prototype,告訴 Spring 這個 Bean 是原型範圍的,從而使用原型模式來創建對象。

<bean id="myBean" class="com.example.MyBean" scope="prototype">
</bean>

單例模式在 Spring 中的應用:

單例範圍(Scope)的 Bean:預設情況下,Spring 中的 Bean 是單例範圍的,這意味著 Spring 容器只會創建一個 Bean 的實例,併在整個應用程式中共用這個實例。這就是單例模式的應用,確保一個類只有一個實例。

使用 singleton 作用域聲明 Bean:雖然預設是單例範圍,但你也可以顯式將 Bean 的作用域聲明為 singleton,以明確表達這一點。

<bean id="myBean" class="com.example.MyBean" scope="singleton">
</bean>

在 Spring 中,原型模式和單例模式的選擇取決於對象的生命周期和狀態需求。如果你需要一個共用狀態的單一實例,可以使用單例模式。如果需要每次請求都獲得一個全新的對象實例,可以使用原型模式。Spring 提供了這兩種範圍的支持,以滿足不同的業務需求。

9 小結

原型模式是一種用於創建對象的設計模式,它通過克隆現有對象來創建新對象,從而提高性能、簡化對象創建和支持動態配置對象的需求。原型模式在需要頻繁創建對象,或者需要保護對象不受修改影響的情況下非常有用。


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

-Advertisement-
Play Games
更多相關文章
  • 1.分組 group by 詳情見,發佈的第七篇博客文章,7- MySQL函數 2.排序 order by 說明:在MySQL中,ORDER BY是一種用於對查詢結果進行排序的關鍵字。它可以根據一列或多列的值,以升序或降序的方式對查詢結果進行排序,使得查詢者可以更加方便 地查看、分析和處理數據。 使 ...
  • 1.分組group by 在MySQL中,GROUP BY的意思是“分組查詢”,它可以根據一個或多個欄位對查詢結果進行分組。 GROUP BY的作用是通過一定的規則將一個數據集劃分成若幹個小的區域,然後針對若幹個小區域進行數據處理。這可以理解為將數據按照某個欄位或者多個欄位進行分組。 使用GROUP ...
  • MySQL資料庫管理 資料庫-->數據表-->行(記錄):用來描述一個對象的信息 列(欄位):用來描述對象的一個屬性 常用的數據類型: int :整型 無符號[0,2^32-1],有符號[-2^31,2^31-1] float :單精度浮點 4位元組32位 double :雙精度浮點 8位元組64位 c ...
  • 在MySQL中,高級查詢是指使用更複雜的查詢語句和操作符來檢索和操作資料庫中的數據。高級查詢可以幫助您更精確地找到所需的信息,並提高查詢的效率和靈活性。 以下是高級查詢的一些常見應用場景和意義: 連接多個表:使用JOIN操作符將多個表連接起來,以便在一次查詢中獲取相關聯的數據。這對於在多個表之間建立 ...
  • 背景: 隨著項目體量越來越大,用戶群體越來越多,用戶的聲音也越來越明顯;關於應用發版之後用戶無感知,導致用戶用的是仍然還是老版本功能,除非用戶手動刷新,否則體驗不到最新的功能;這樣的體驗非常不好,於是我們團隊針對該問題給出了相應的解決方案來處理;技術棧:vue3+ts+vite+ant-design ...
  • 相比用戶停留時間短、用完即走的 Web 頁面,桌面 QQ 用戶在一次登錄後,可能會掛機一周以上,這段期間,如果沒有嚴格控制好 QQ 記憶體占用,那麼結果可能是用戶交互響應變慢、甚至 Crash。在系統監控工具里,高記憶體占用也會被直觀地反映出來,帶來不好的口碑。MAC QQ 灰度期間,也聽到了一些用戶關... ...
  • 介紹 ESLint 是一個根據方案識別並報告 ECMAScript/JavaScript 代碼問題的工具,其目的是使代碼風格更加一致並避免錯誤。在很多地方它都與 JSLint 和 JSHint 類似,除了: ESLint 使用 Espree 對 JavaScript 進行解析。 ESLint 在代碼 ...
  • 這是一個講解DDD落地的文章系列,作者是《實現領域驅動設計》的譯者滕雲。本文章系列以一個真實的並已成功上線的軟體項目——碼如雲(https://www.mryqr.com)為例,系統性地講解DDD在落地實施過程中的各種典型實踐,以及在面臨實際業務場景時的諸多取捨。 本系列包含以下文章: DDD入門 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...