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

来源: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
  • 通過WPF的按鈕、文本輸入框實現了一個簡單的SpinBox數字輸入用戶組件並可以通過數據綁定數值和步長。本文中介紹了通過Xaml代碼實現自定義組件的佈局,依賴屬性的定義和使用等知識點。 ...
  • 以前,我看到一個朋友在對一個系統做初始化的時候,通過一組魔幻般的按鍵,調出來一個隱藏的系統設置界面,這個界面在常規的菜單或者工具欄是看不到的,因為它是一個後臺設置的關鍵界面,不公開,同時避免常規用戶的誤操作,它是作為一個超級管理員的入口功能,這個是很不錯的思路。其實Winform做這樣的處理也是很容... ...
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他的程式每次關閉時就會自動崩潰,一直找不到原因讓我幫忙看一下怎麼回事,這位朋友應該是第二次找我了,分析了下 dump 還是挺經典的,拿出來給大家分享一下吧。 二:WinDbg 分析 1. 為什麼會崩潰 找崩潰原因比較簡單,用 !analyze -v 命 ...
  • 在一些報表模塊中,需要我們根據用戶操作的名稱,來動態根據人員姓名,更新報表的簽名圖片,也就是電子手寫簽名效果,本篇隨筆介紹一下使用FastReport報表動態更新人員簽名圖片。 ...
  • 最新內容優先發佈於個人博客:小虎技術分享站,隨後逐步搬運到博客園。 創作不易,如果覺得有用請在Github上為博主點亮一顆小星星吧! 博主開始學習編程於11年前,年少時還只會使用cin 和cout ,給單片機點點燈。那時候,類似async/await 和future/promise 模型的認知還不是 ...
  • 之前在阿裡雲ECS 99元/年的活動實例上搭建了一個測試用的MINIO服務,以前都是直接當基礎設施來使用的,這次準備自己學一下S3相容API相關的對象存儲開發,因此有了這個小工具。目前僅包含上傳功能,後續計劃開發一個類似圖床的對象存儲應用。 ...
  • 目錄簡介快速入門安裝 NuGet 包實體類User資料庫類DbFactory增刪改查InsertSelectUpdateDelete總結 簡介 NPoco 是 PetaPoco 的一個分支,具有一些額外的功能,截至現在 github 星數 839。NPoco 中文資料沒多少,我是被博客園群友推薦的, ...
  • 前言 前面使用 Admin.Core 的代碼生成器生成了通用代碼生成器的基礎模塊 分組,模板,項目,項目模型,項目欄位的基礎功能,本篇繼續完善,實現最核心的模板生成功能,並提供生成預覽及代碼文件壓縮下載 準備 首先清楚幾個模塊的關係,如何使用,簡單畫一個流程圖 前面完成了基礎的模板組,模板管理,項目 ...
  • 假設需要實現一個圖標和文本結合的按鈕 ,普通做法是 直接重寫該按鈕的模板; 如果想作為通用的呢? 兩種做法: 附加屬性 自定義控制項 推薦使用附加屬性的形式 第一種:附加屬性 創建Button的附加屬性 ButtonExtensions 1 public static class ButtonExte ...
  • 在C#中,委托是一種引用類型的數據類型,允許我們封裝方法的引用。通過使用委托,我們可以將方法作為參數傳遞給其他方法,或者將多個方法組合在一起,從而實現更靈活的編程模式。委托類似於函數指針,但提供了類型安全和垃圾回收等現代語言特性。 基本概念 定義委托 定義委托需要指定它所代表的方法的原型,包括返回類 ...