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

来源: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 微服務框架,幫助我們輕鬆構建和管理微服務應用。 本框架不僅支持 Consul 服務註 ...
  • 先看一下效果吧: 如果不會寫動畫或者懶得寫動畫,就直接交給Blend來做吧; 其實Blend操作起來很簡單,有點類似於在操作PS,我們只需要設置關鍵幀,滑鼠點來點去就可以了,Blend會自動幫我們生成我們想要的動畫效果. 第一步:要創建一個空的WPF項目 第二步:右鍵我們的項目,在最下方有一個,在B ...
  • Prism:框架介紹與安裝 什麼是Prism? Prism是一個用於在 WPF、Xamarin Form、Uno 平臺和 WinUI 中構建鬆散耦合、可維護和可測試的 XAML 應用程式框架 Github https://github.com/PrismLibrary/Prism NuGet htt ...
  • 在WPF中,屏幕上的所有內容,都是通過畫筆(Brush)畫上去的。如按鈕的背景色,邊框,文本框的前景和形狀填充。藉助畫筆,可以繪製頁面上的所有UI對象。不同畫筆具有不同類型的輸出( 如:某些畫筆使用純色繪製區域,其他畫筆使用漸變、圖案、圖像或繪圖)。 ...
  • 前言 嗨,大家好!推薦一個基於 .NET 8 的高併發微服務電商系統,涵蓋了商品、訂單、會員、服務、財務等50多種實用功能。 項目不僅使用了 .NET 8 的最新特性,還集成了AutoFac、DotLiquid、HangFire、Nlog、Jwt、LayUIAdmin、SqlSugar、MySQL、 ...
  • 本文主要介紹攝像頭(相機)如何採集數據,用於類似攝像頭本地顯示軟體,以及流媒體數據傳輸場景如傳屏、視訊會議等。 攝像頭採集有多種方案,如AForge.NET、WPFMediaKit、OpenCvSharp、EmguCv、DirectShow.NET、MediaCaptre(UWP),網上一些文章以及 ...
  • 前言 Seal-Report 是一款.NET 開源報表工具,擁有 1.4K Star。它提供了一個完整的框架,使用 C# 編寫,最新的版本採用的是 .NET 8.0 。 它能夠高效地從各種資料庫或 NoSQL 數據源生成日常報表,並支持執行複雜的報表任務。 其簡單易用的安裝過程和直觀的設計界面,我們 ...
  • 背景需求: 系統需要對接到XXX官方的API,但因此官方對接以及管理都十分嚴格。而本人部門的系統中包含諸多子系統,系統間為了穩定,程式間多數固定Token+特殊驗證進行調用,且後期還要提供給其他兄弟部門系統共同調用。 原則上:每套系統都必須單獨接入到官方,但官方的接入複雜,還要官方指定機構認證的證書 ...
  • 本文介紹下電腦設備關機的情況下如何通過網路喚醒設備,之前電源S狀態 電腦Power電源狀態- 唐宋元明清2188 - 博客園 (cnblogs.com) 有介紹過遠程喚醒設備,後面這倆天瞭解多了點所以單獨加個隨筆 設備關機的情況下,使用網路喚醒的前提條件: 1. 被喚醒設備需要支持這WakeOnL ...
  • 前言 大家好,推薦一個.NET 8.0 為核心,結合前端 Vue 框架,實現了前後端完全分離的設計理念。它不僅提供了強大的基礎功能支持,如許可權管理、代碼生成器等,還通過採用主流技術和最佳實踐,顯著降低了開發難度,加快了項目交付速度。 如果你需要一個高效的開發解決方案,本框架能幫助大家輕鬆應對挑戰,實 ...