深入淺出設計模式——創建型模式之原型模式 Prototype

文章目錄

  • 原型模式簡介
  • 原型模式結構
  • 關于克隆方法:淺拷貝/深拷貝
  • 原型模式代碼實例
    • 定義原型類和克隆方法
    • 客戶端使用代碼示例
      • 示例一:淺拷貝
    • 示例二:深拷貝
  • 原型模式總結
    • 開閉原則

代碼倉庫

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

定義看起來有點繞口,不妨簡單的理解為:原型模式就是用來克隆對象的。

舉個例子,比如有一天,周杰倫到奶茶店點了一份不加冰的原味奶茶,你說我是周杰倫的忠實粉,我也要一份跟周杰倫一樣的。
在這里插入圖片描述

即便Jungle讀書少,Jungle也清晰地記得中學生物課本上提到過的克隆羊“多利”。雖然多利壽命不長,但它的出現對“克隆(Clone)”技術意義重大。克隆,直觀說就是從原有生物體上取體細胞,然后無性繁殖出有完全相同基因的個體或種群。這么說來中國的克隆技術其實是世界領先的,因為孫悟空拔一根毫毛變出許多一模一樣的孫悟空的傳說本質上就是克隆!而本文將要介紹的原型模式,將克隆技術應用到了軟件設計層面。

原型模式簡介

原型模式通過復制一個已有對象來獲取更多相同或者相似的對象。原型模式定義如下:

使用原型實例指定待創建對象的類型,并且通過復制這個原型來創建新的對象。

原型模式的工作原理是將一個原型對象傳給要發動創建的對象(即客戶端對象),這個要發動創建的對象通過請求原型對象復制自己來實現創建過程。從工廠方法角度而言,創建新對象的工廠就是原型類自己。軟件系統中有些對象的創建過程比較復雜,且有時需要頻繁創建,原型模式通過給出一個原型對象來指明所要創建的對象的類型,然后用復制這個原型對象的辦法創建出更多同類型的對象,這就是原型模式的意圖所在。

原型模式結構

在這里插入圖片描述

關于克隆方法:淺拷貝/深拷貝

在這里插入圖片描述

原型模式代碼實例

明天就是周一了,Jungle又陷入了苦惱中,因為作業還沒完成。于是Jungle想拿著哥哥Single的作業來抄一份。雖然抄襲作業并不好,但是邊抄邊學借鑒一下也是可以的。于是乎,Jungle開始動起手來……

作業包含幾個部分:姓名(name)、學號(idNum)、模型(workModel)。首先定義一個workModel類:

// work model類
// 作為復雜的成員對象,供ConcreteWork引用。
class WorkModel {
public:std::string modelName;WorkModel() : modelName("") {}WorkModel(const std::string& iName) : modelName(iName) {}void setWorkModelName(const std::string& iName) {this->modelName = iName;}std::string getWorkModelName() const {return modelName;}// 深拷貝構造函數// 深拷貝構造函數防止多個對象共享同一個內存(避免淺拷貝問題)。// std::string 本身已經重載了拷貝構造函數和賦值運算符,實現了深拷貝的語義。WorkModel(const WorkModel& other) : modelName(other.modelName) {}
};  

該實例UML圖如下:
在這里插入圖片描述

定義原型類和克隆方法

// 抽象原型類PrototypeWork
// 定義抽象接口clone(),具體原型類必須實現該方法。
class PrototypeWork {
public:PrototypeWork() {}virtual ~PrototypeWork() {}virtual PrototypeWork* clone() = 0;virtual void printWorkInfo() const = 0;
};// 具體原型類PrototypeWork
class ConcreteWork: public PrototypeWork {
public:ConcreteWork(const string& iName, int iIdNum, const string& modelName): name(iName), idNum(iIdNum), workModel(new WorkModel(modelName)) {}// 深拷貝構造函數ConcreteWork(const ConcreteWork& other): name(other.name), idNum(other.idNum), workModel(new WorkModel(*other.workModel)) {}// 深拷貝賦值運算符// ConcreteWork& operator=(const ConcreteWork& other) {//     if (this != &other) {//         name = other.name;//         idNum = other.idNum;//         delete workModel;//         workModel = new WorkModel(*other.workModel);//     }//     return *this;// }// 克隆接口實現(返回深拷貝)PrototypeWork* clone() override {return new ConcreteWork(*this);}~ConcreteWork() {delete workModel;}// 打印work信息void printWorkInfo() const override {std::cout << "Name: " << name << std::endl;std::cout << "IdNum: " << idNum << std::endl;std::cout << "ModelName: " << workModel->getWorkModelName() << std::endl;}// 新增set方法void setName(const std::string& newName) {name = newName;}void setIdNum(int newIdNum) {idNum = newIdNum;}void setModel(WorkModel* newModel) {if (workModel != nullptr) {delete workModel;}workModel = newModel;}// 新增get方法std::string getName() const {return name;}int getIdNum() const {return idNum;}WorkModel* getModel() const {return workModel;}private:string name;int idNum;WorkModel* workModel;
};

客戶端使用代碼示例

示例一:淺拷貝

#include "PrototypePattern.h"int main() {
// #if 0
// // 下面的代碼將不會被編譯,也不會執行ConcreteWork *singleWork = new ConcreteWork("Single",1001,"Single_Model");printf("\nSingle的作業:\n");singleWork->printWorkInfo();printf("\njungle直接抄作業……\n");ConcreteWork *jungleWork = singleWork;printf("\nJungle的作業:\n");jungleWork->printWorkInfo();// 抄完改名字和學號,否則會被老師查出來printf("\njungle抄完改名字和學號,否則會被老師查出來……\n");jungleWork->setName("jungle");jungleWork->setIdNum(1002);WorkModel *jungleModel = new WorkModel();jungleModel->setWorkModelName("Jungle_Model");jungleWork->setModel(jungleModel);// 檢查下是否改對了printf("\nSingle的作業:\n");singleWork->printWorkInfo();printf("\nJungle的作業:\n");jungleWork->printWorkInfo();
// #endif 
#if 0
// 下面的代碼將不會被編譯,也不會執行ConcreteWork *singleWork = new ConcreteWork("Single", 1001, "Single_Model");printf("\nSingle的作業:\n");// clone() 返回 PrototypeWork*,需類型轉換ConcreteWork* jungleWork = dynamic_cast<ConcreteWork*>(singleWork->clone());printf("\njungle直接抄作業……\n");// 抄完改名字和學號,否則會被老師查出來printf("\njungle抄完改名字和學號,否則會被老師查出來……\n");jungleWork->setName("jungle");jungleWork->setIdNum(1002);WorkModel *jungleModel = new WorkModel();jungleModel->setWorkModelName("Jungle_Model");jungleWork->setModel(jungleModel);// 檢查下是否改對了printf("\nSingle的作業:\n");singleWork->printWorkInfo();printf("\nJungle的作業:\n");jungleWork->printWorkInfo();delete singleWork;delete jungleWork;
#endif return 0;
}

在這里插入圖片描述
顯然,這不是我們想要的結果。接下來我們使用clone方法。

示例二:深拷貝


```cpp
#include "PrototypePattern.h"int main() {
#if 0
// 下面的代碼將不會被編譯,也不會執行ConcreteWork *singleWork = new ConcreteWork("Single",1001,"Single_Model");printf("\nSingle的作業:\n");singleWork->printWorkInfo();printf("\njungle直接抄作業……\n");ConcreteWork *jungleWork = singleWork;printf("\nJungle的作業:\n");jungleWork->printWorkInfo();// 抄完改名字和學號,否則會被老師查出來printf("\njungle抄完改名字和學號,否則會被老師查出來……\n");jungleWork->setName("jungle");jungleWork->setIdNum(1002);WorkModel *jungleModel = new WorkModel();jungleModel->setWorkModelName("Jungle_Model");jungleWork->setModel(jungleModel);// 檢查下是否改對了printf("\nSingle的作業:\n");singleWork->printWorkInfo();printf("\nJungle的作業:\n");jungleWork->printWorkInfo();
#endif 
// #if 0
// 下面的代碼將不會被編譯,也不會執行ConcreteWork *singleWork = new ConcreteWork("Single", 1001, "Single_Model");printf("\nSingle的作業:\n");singleWork->printWorkInfo();// clone() 返回 PrototypeWork*,需類型轉換printf("\njungle直接抄作業……\n");ConcreteWork* jungleWork = dynamic_cast<ConcreteWork*>(singleWork->clone());printf("\nJungle的作業:\n");jungleWork->printWorkInfo();// 抄完改名字和學號,否則會被老師查出來printf("\njungle抄完改名字和學號,否則會被老師查出來……\n");jungleWork->setName("jungle");jungleWork->setIdNum(1002);WorkModel *jungleModel = new WorkModel();jungleModel->setWorkModelName("Jungle_Model");jungleWork->setModel(jungleModel);// 檢查下是否改對了printf("\nSingle的作業:\n");singleWork->printWorkInfo();printf("\nJungle的作業:\n");jungleWork->printWorkInfo();delete singleWork;delete jungleWork;
// #endif return 0;
}

在這里插入圖片描述

原型模式總結

在這里插入圖片描述

開閉原則

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

之后我會持續更新,如果喜歡我的文章,請記得一鍵三連哦,點贊關注收藏,你的每一個贊每一份關注每一次收藏都將是我前進路上的無限動力 !!!↖(▔▽▔)↗感謝支持!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917235.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917235.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917235.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

.NET 10 中的新增功能系列文章3—— .NET MAUI 中的新增功能

.NET 10 預覽版 6 中的 .NET MAUI.NET 10 預覽版 5 中的.NET MAUI.NET 10 預覽版 4 中的 .NET MAUI.NET 10 預覽版 3 中的 .NET MAUI.NET 10 預覽版 2 中的 .NET MAUI.NET 10 預覽版 1 中的 .NET MAUI 一、MediaPicker 增強功能&#xff08;預覽版6&#xff09; .NET 10 預覽…

MT Photos圖庫部署詳解:Docker搭建+貝銳蒲公英異地組網遠程訪問

如今&#xff0c;私有化部署輕量級圖床/圖庫系統&#xff0c;已經成為越來越多用戶的高頻需求。而MT Photos&#xff0c;正是一款非常適合在Docker環境下運行的自托管圖床/圖庫系統。MT Photos基于Node.js與Vue構建&#xff0c;界面簡潔美觀&#xff0c;支持多用戶權限管理、多…

解決dbeaver連接不上oceanbase數據庫的問題

解決dbeaver連接不上oceanbase數據庫的問題 問題&#xff1a; 使用dbeaver連接oceanbase數據庫報錯如下&#xff1a; ORA-00900: You have an error in your SQL syntax; check the manual that corresponds to your OceanBase version for the right syntax to use near ‘dat…

Kafka——請求是怎么被處理的?

引言在分布式消息系統中&#xff0c;請求處理機制是連接客戶端與服務端的"神經中樞"。無論是生產者發送消息、消費者拉取數據&#xff0c;還是集群內部的元數據同步&#xff0c;都依賴于高效的請求處理流程。Apache Kafka作為高性能消息隊列的代表&#xff0c;其請求…

區塊鏈技術如何確保智能合約的安全性和可靠性?

智能合約作為區塊鏈上自動執行的可編程協議&#xff0c;其安全性和可靠性直接決定了區塊鏈應用的信任基礎。區塊鏈通過底層技術架構、密碼學工具和機制設計的多重保障&#xff0c;構建了智能合約的安全防線。以下從技術原理、核心機制和實踐保障三個維度展開分析&#xff1a;一…

2020 年 NOI 最后一題題解

問題描述2020 年 NOI 最后一題是一道結合圖論、動態規劃與狀態壓縮的綜合性算法題&#xff0c;題目圍繞 "疫情期間的物資配送" 展開&#xff0c;具體要求如下&#xff1a;給定一個有向圖 G (V, E)&#xff0c;其中節點代表城市&#xff0c;邊代表連接城市的道路。每個…

加密與安全

目錄 一、URL編碼&#xff1a; 二、Base64編碼&#xff1a; 三、哈希算法&#xff1a; 四、Hmac算法&#xff1a; 五、對稱加密算法&#xff1a; 一、URL編碼&#xff1a; URL編碼是瀏覽器發送數據給服務器時使用的編碼&#xff0c;它通常附加在URL的參數部分。之所以需要…

EasyExcel 公式計算大全

EasyExcel 是基于 Apache POI 的封裝&#xff0c;主要專注于簡化 Excel 的讀寫操作&#xff0c;對于公式計算的支持相對有限。以下是 EasyExcel 中處理公式計算的全面指南&#xff1a;1. 基本公式寫入1.1 寫入簡單公式Data public class FormulaData {ExcelProperty("數值…

2025年AI+數模競賽培訓意見征集-最后一輪

在過去幾天的“AI時代下2025年數模競賽培訓課程需求調研緊急征集”我們收到了大量老師、學生的反饋。我們通過大家的實際需求&#xff0c;編寫了下述2025年AI時代下最新的數學建模競賽教學課程課程表&#xff0c;具體授課內容以及相關課件、支撐材料都將會免費發布&#xff0c;…

Qwen2 RotaryEmbedding 位置編碼僅僅是第一層有嗎

Qwen2 RotaryEmbedding 位置編碼僅僅是第一層有嗎,還是全部層都有 Qwen2 模型中的 Rotary Embedding(旋轉位置編碼)是應用于所有 Transformer 層 的,而非僅第一層。 1. Transformer 架構的核心邏輯 Qwen2 基于 Decoder-only Transformer 架構,而位置編碼(如 Rotary Emb…

CNN卷積神經網絡之LeNet和AlexNet經典網絡模型(三)

CNN卷積神經網絡之LeNet和AlexNet經典網絡模型&#xff08;三&#xff09; 文章目錄CNN卷積神經網絡之LeNet和AlexNet經典網絡模型&#xff08;三&#xff09;深度學習兩大經典 CNN 模型速覽1. LeNet-5&#xff1a;CNN 的開山之作&#xff08;1998&#xff09;2. AlexNet&#…

江協科技STM32 12-2 BKP備份寄存器RTC實時時鐘

這一節我們要講的主要內容是RTC實時時鐘&#xff0c;實時時鐘本質上是一個定時器&#xff0c;但是這個定時器是專門用來產生年月日時分秒&#xff0c;這種日期和時間信息的。所以學會了STM32的RTC就可以在STM32內部擁有一個獨立運行的鐘表。想要記錄或讀取日期和時間&#xff0…

【10】大恒相機SDK C++開發 ——對相機采集的原圖像數據IFrameData裁剪ROI 實時顯示在pictureBox中,3種方法實現(效率不同)

文章目錄1 在回調函數中實現2 獨立封裝調用2.1 獲取圖像寬、高、pBuffer、channel2.2 內存圖像數據截取ROI并顯示2.3 回調函數調用3 for循環嵌套 方法24 for循環嵌套 方法35 按行復制數據提高效率&#xff0c;但很耗內存6 unsafe代碼 解釋及注意事項 看我另一篇文章7 ConvertTo…

ubuntu22.04系統入門 linux入門(二) 簡單命令 多實踐以及相關文件管理命令

以下有免費的4090云主機提供ubuntu22.04系統的其他入門實踐操作 地址&#xff1a;星宇科技 | GPU服務器 高性能云主機 云服務器-登錄 相關兌換碼星宇社區---4090算力卡免費體驗、共享開發社區-CSDN博客 之所以推薦給大家使用&#xff0c;是因為上面的云主機目前是免費使用的…

分布式ID方案(標記)

一、參考文章-標記 分布式ID方案有哪些&#xff1f;雪花算法如何搞定時鐘回撥和動態機器ID&#xff1f; 二、應用 1.百度 uid-generator github項目地址 原理參考 2.百度 uid-generator 擴展應用 燈官網 燈 項目代碼 lamp-util 單元模塊 lamp-util 單元模塊子模塊 lamp-…

std::map 加鎖

在并發環境下使用std::map&#xff0c;必須采取同步措施。 在并發環境下對 std::map 進行不加鎖的讀寫操作會導致嚴重的線程安全問題&#xff0c;主要會產生以下幾種問題&#xff1a; ?? 主要風險與后果數據競爭&#xff08;Data Race&#xff09; 當多個線程同時修改同一個鍵…

學習筆記090——Ubuntu 中 UFW 防火墻的使用

文章目錄1、允許特定的端口訪問2、允許特定 IP 訪問某個端口3、允許某個范圍的端口4、查看 UFW 狀態5、重新加載 UFW6、啟用 UFW7、關閉 UFW1、允許特定的端口訪問 # 允許 TCP 端口&#xff08;例如 80&#xff09;&#xff1a; sudo ufw allow 80/tcp# 允許 UDP 端口&#xf…

移動端 WebView 內存泄漏與性能退化問題如何排查 實戰調試方法匯總

在混合 App 應用中&#xff0c;WebView 頁面常承載復雜業務邏輯與交互。隨著用戶使用時間增長&#xff0c;特別在切換多個頁面或反復打開界面后&#xff0c;常常會出現性能下降、頁面卡頓、甚至白屏崩潰等現象。這通常是因為頁面存在內存泄漏、事件監聽未解綁或垃圾回收阻塞導致…

JSON 對象在瀏覽器中順序與后端接口返回不一致的問題

一、問題描述 后端接口返回一個字典表的JSON對象&#xff0c;頁面展示排序與預期排序不一致。 在瀏覽器調試面板Response中看到接口原始響應字符串&#xff0c;是期望順序&#xff1a;在Preview中看到&#xff0c; key “22” 被提到最前&#xff0c;順序發生變化&#xff1a;頁…

Spring MVC數據傳遞全攻略

Spring MVC數據傳遞一、前端到后端的數據傳遞1. 使用 RequestParam 傳遞簡單參數2. 使用 PathVariable傳遞路徑參數3. 使用RequestBody傳遞 JSON 數據二、后端到前端的數據傳遞1. 使用Model或 ModelAndView傳遞數據到前端2. 使用HttpServletResponse直接寫回數據3.使用Response…