設計模式:原型模式(Prototype Pattern)

文章目錄

    • 一、原型模式的概念
    • 二、原型模式的結構
    • 三、原型注冊機制
    • 四、完整示例代碼

一、原型模式的概念

??原型模式是一種創建型設計模式, 使你能夠復制已有對象, 而又無需使代碼依賴它們所屬的類。通過復制(克隆)已有的實例來創建新的對象,而不是通過 new 來實例化。

  • 意圖:在對象創建代價較大、或需要保留對象當前狀態時,通過克隆來生成新對象。
  • 核心思想:每個類實現一個 clone() 接口,用于復制自身。

在這里插入圖片描述
優點:

  • 隱藏對象創建細節,對客戶端透明。
  • 提高性能(適合復雜對象復制)。
  • 動態擴展對象種類,不需要修改工廠類。

缺點:

  • 對象內部含有復雜引用時,深拷貝實現復雜。
  • 如果對象的構造過程并不復雜,使用原型模式反而增加代碼復雜度。

二、原型模式的結構

角色組成:

  • Prototype(抽象原型類):定義了 clone() 方法的接口。
  • ConcretePrototype(具體原型類):實現 clone(),復制自身。
  • Client(客戶類):通過調用 clone() 來創建新對象,而不是直接 new。

基本實現:
在這里插入圖片描述
UML類圖:
在這里插入圖片描述
示例代碼:

#include <iostream>
#include <string>
using namespace std;// 抽象原型類
class Prototype {
public:virtual ~Prototype() {}virtual Prototype* clone() const = 0;virtual void show() const = 0;
};// 具體原型類 A
class ConcretePrototypeA : public Prototype {
public:ConcretePrototypeA(const string& name) : name(name) {}Prototype* clone() const override {return new ConcretePrototypeA(*this); // 調用拷貝構造}void show() const override {cout << "ConcretePrototypeA: " << name << endl;}
private:string name;
};// 具體原型類 B
class ConcretePrototypeB : public Prototype {
public:ConcretePrototypeB(int value) : value(value) {}Prototype* clone() const override {return new ConcretePrototypeB(*this); // 調用拷貝構造}void show() const override {cout << "ConcretePrototypeB: value=" << value << endl;}
private:int value;
};// 使用示例
int main() {Prototype* p1 = new ConcretePrototypeA("原型A");Prototype* p2 = new ConcretePrototypeB(42);Prototype* c1 = p1->clone(); // 克隆APrototype* c2 = p2->clone(); // 克隆Bc1->show();c2->show();delete p1;delete p2;delete c1;delete c2;return 0;
}

原型模式(Prototype Pattern)示例,用來克隆 QWidget 界面
場景:

  • 有一個復雜的界面 CustomWidget(包含標簽和按鈕)。
  • 界面創建比較復雜,不想每次都 new。
  • 通過原型模式,我們直接 clone() 來復制已有的界面。

代碼示例:

#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QString>// ============ 抽象原型類 ============
class PrototypeWidget : public QWidget {
public:PrototypeWidget(QWidget *parent = nullptr) : QWidget(parent) {}virtual ~PrototypeWidget() {}virtual PrototypeWidget* clone() const = 0;  // 原型接口
};// ============ 具體原型類 ============
class CustomWidget : public PrototypeWidget {
public:CustomWidget(const QString &title, const QString &buttonText, QWidget *parent = nullptr): PrototypeWidget(parent), m_title(title), m_buttonText(buttonText) {QVBoxLayout *layout = new QVBoxLayout(this);m_label = new QLabel(m_title, this);m_button = new QPushButton(m_buttonText, this);layout->addWidget(m_label);layout->addWidget(m_button);setLayout(layout);resize(220, 120);}// 克隆自身PrototypeWidget* clone() const override {return new CustomWidget(m_title, m_buttonText);}// ====== 擴展功能:支持修改部分內容 ======void setTitle(const QString &title) {m_title = title;if (m_label) m_label->setText(m_title);}void setButtonText(const QString &text) {m_buttonText = text;if (m_button) m_button->setText(m_buttonText);}private:QString m_title;QString m_buttonText;QLabel *m_label{nullptr};QPushButton *m_button{nullptr};
};// ============ 使用示例 ============
int main(int argc, char *argv[]) {QApplication app(argc, argv);// 原型窗口CustomWidget *prototype = new CustomWidget("原型窗口", "點擊我");prototype->setWindowTitle("原型窗口");prototype->move(100, 100);prototype->show();// 克隆窗口 1(修改標題和按鈕文字)CustomWidget *w1 = static_cast<CustomWidget*>(prototype->clone());w1->setWindowTitle("克隆窗口 1");w1->setTitle("我是克隆1");w1->setButtonText("確認");w1->move(350, 100);w1->show();// 克隆窗口 2(只修改按鈕文字)CustomWidget *w2 = static_cast<CustomWidget*>(prototype->clone());w2->setWindowTitle("克隆窗口 2");w2->setButtonText("取消");w2->move(600, 100);w2->show();return app.exec();
}

三、原型注冊機制

基本實現:
在這里插入圖片描述
UML類圖:
在這里插入圖片描述
示例:支持原型注冊

#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QString>
#include <QMap>// ============ 抽象原型類 ============
class PrototypeWidget : public QWidget {
public:PrototypeWidget(QWidget *parent = nullptr) : QWidget(parent) {}virtual ~PrototypeWidget() {}virtual PrototypeWidget* clone() const = 0;  // 原型接口
};// ============ 具體原型類 ============
class CustomWidget : public PrototypeWidget {
public:CustomWidget(const QString &title, const QString &buttonText, QWidget *parent = nullptr): PrototypeWidget(parent), m_title(title), m_buttonText(buttonText){QVBoxLayout *layout = new QVBoxLayout(this);m_label = new QLabel(m_title, this);m_button = new QPushButton(m_buttonText, this);layout->addWidget(m_label);layout->addWidget(m_button);setLayout(layout);resize(220, 120);}// 克隆自身PrototypeWidget* clone() const override {return new CustomWidget(m_title, m_buttonText);}// ====== 擴展功能:支持修改部分內容 ======void setTitle(const QString &title) {m_title = title;if (m_label) m_label->setText(m_title);}void setButtonText(const QString &text) {m_buttonText = text;if (m_button) m_button->setText(m_buttonText);}private:QString m_title;QString m_buttonText;QLabel *m_label{nullptr};QPushButton *m_button{nullptr};
};// ============ 原型管理器 ============
class PrototypeManager {
public:~PrototypeManager() {qDeleteAll(m_prototypes);}void registerPrototype(const QString &name, PrototypeWidget *prototype) {if (m_prototypes.contains(name)) {delete m_prototypes[name];}m_prototypes[name] = prototype;}PrototypeWidget* create(const QString &name) {if (m_prototypes.contains(name)) {return m_prototypes[name]->clone();}return nullptr;}private:QMap<QString, PrototypeWidget*> m_prototypes;
};// ============ 使用示例 ============
int main(int argc, char *argv[]) {QApplication app(argc, argv);PrototypeManager manager;// 注冊不同類型的窗口原型manager.registerPrototype("login", new CustomWidget("登錄窗口", "登錄"));manager.registerPrototype("register", new CustomWidget("注冊窗口", "注冊"));manager.registerPrototype("alert", new CustomWidget("警告", "確定"));// 克隆出 登錄窗口CustomWidget *w1 = static_cast<CustomWidget*>(manager.create("login"));if (w1) {w1->setWindowTitle("克隆 - 登錄");w1->move(100, 100);w1->show();}// 克隆出 注冊窗口,并修改按鈕文字CustomWidget *w2 = static_cast<CustomWidget*>(manager.create("register"));if (w2) {w2->setWindowTitle("克隆 - 注冊");w2->setButtonText("立即注冊");w2->move(350, 100);w2->show();}// 克隆出 警告窗口CustomWidget *w3 = static_cast<CustomWidget*>(manager.create("alert"));if (w3) {w3->setWindowTitle("克隆 - 警告");w3->move(600, 100);w3->show();}return app.exec();
}

四、完整示例代碼

假設有一套 圖形(Shape)類,包含圓形(Circle)、矩形(Rectangle),需要通過原型拷貝的方式創建新對象。

#include <QCoreApplication>
#include <QDebug>
#include <QString>
#include <QMap>// Prototype 接口
class Shape {
public:virtual ~Shape() {}virtual Shape* clone() const = 0;virtual void draw() const = 0;
};// 具體原型類:圓形
class Circle : public Shape {
public:Circle(int r = 0) : radius(r) {}Circle(const Circle& other) { radius = other.radius; }Shape* clone() const override {return new Circle(*this); // 深拷貝}void draw() const override {qDebug() << "繪制一個圓, 半徑 =" << radius;}private:int radius;
};// 具體原型類:矩形
class Rectangle : public Shape {
public:Rectangle(int w = 0, int h = 0) : width(w), height(h) {}Rectangle(const Rectangle& other) {width = other.width;height = other.height;}Shape* clone() const override {return new Rectangle(*this);}void draw() const override {qDebug() << "繪制一個矩形, 寬 =" << width << " 高 =" << height;}private:int width;int height;
};// PrototypeManager 原型管理器
class PrototypeManager {
public:void registerPrototype(const QString& name, Shape* prototype) {prototypes[name] = prototype;}void unregisterPrototype(const QString& name) {prototypes.remove(name);}Shape* create(const QString& name) {if (prototypes.contains(name)) {return prototypes[name]->clone();}return nullptr;}private:QMap<QString, Shape*> prototypes;
};// 客戶端使用
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);PrototypeManager manager;// 注冊原型manager.registerPrototype("circle", new Circle(10));manager.registerPrototype("rectangle", new Rectangle(20, 30));// 克隆對象Shape* c1 = manager.create("circle");Shape* r1 = manager.create("rectangle");if (c1) c1->draw();if (r1) r1->draw();// 再次克隆,得到新的對象Shape* c2 = manager.create("circle");if (c2) c2->draw();// 清理內存delete c1;delete r1;delete c2;return a.exec();
}

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

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

相關文章

Linux系統網絡管理

一、網絡參數配置1、圖形化配置#開啟 [rootlocalhost ~]# systemctl start NetworkManager #關閉 [rootlocalhost ~]# systemctl stop NetworkManager #關閉并開機不自啟 [rootlocalhost ~]# systemctl disable --now NetworkManager #開啟并開機自啟 [rootlocalhost ~]# syste…

服務器初始化

服務器初始化文章目錄服務器初始化1. 配置國內 Yum 源&#xff08;加速軟件安裝&#xff09;2. 更新系統與安裝必備工具3. 網絡連接驗證4. 配置主機名5. 同步時間6. 配置防火墻 (兩種方式)6.1 iptables整體思路詳細步驟第 1 步&#xff1a;停止并禁用 Firewalld第 2 步&#xf…

基于YOLOv11訓練無人機視角Visdrone2019數據集

【閑魚服務】 基于YOLOv11訓練無人機視角Visdrone2019數據集Visdrone2019數據集介紹數據集格式數據預處理yolov11模型訓練數據分布情況可視化訓練結果Visdrone2019數據集介紹 VisDrone 數據集 是由中國天津大學機器學習和數據挖掘實驗室 AISKYEYE 團隊創建的大規模基準。它包含…

基于Springboot 的智能化社區物業管理平臺的設計與實現(代碼+數據庫+LW)

摘 要隨著智慧社區的普及&#xff0c;傳統的物業管理方式已經無法滿足現代社區的需求。目前&#xff0c;很多社區管理中存在信息不暢通、工作效率低以及居民服務體驗不佳等問題。為了解決這些問題&#xff0c;我們基于SpringBoot框架開發了一套智能化社區物業管理平臺&#xf…

【深度學習新浪潮】SAM 2實戰:Meta新一代視頻分割模型的實時應用與Python實現

引言:從圖像到視頻的分割革命 上周AI領域最引人注目的計算機視覺進展,當屬Meta在SAM(Segment Anything Model)基礎上推出的SAM 2模型持續引發的技術熱潮。盡管SAM 2最初發布于2024年,但最新更新的2.1版本(2024年9月發布)憑借其突破性的實時視頻分割能力,在自動駕駛、影…

sqli-labs靶場安裝與使用指導教程(3種方法:通用版、php7版、Docker版)

目錄 一、SQLI-LABS靶場 1、核心特點 2、關卡難度 二、源碼安裝法 1、開啟Web服務和數據庫服務 2、靶場源碼下載 &#xff08;1&#xff09;通用版本 &#xff08;2&#xff09;PHP7版本 3、部署sqli-labs靶場 &#xff08;1&#xff09;確認網站根目錄位置 &#x…

從零開始配置前端環境及必要軟件安裝

從零開始配置前端環境及必要軟件安裝一、安裝編輯器二、安裝瀏覽器三、安裝Git版本控制工具四、Node.js 和 npm 環境變量配置1. 安裝 Node.js 和 npm2. 配置全局模塊和緩存目錄3. 設置環境變量4. 更換 npm 鏡像源5. 測試配置五、hosts文件六、輔助應用markdown&#xff08;筆記…

神經網絡模型搭建及手寫數字識別案例

代碼實現&#xff1a;import torch print(torch.__version__) from torch import nn from torch.utils.data import DataLoader from torchvision import datasets from torchvision.transforms import ToTensor training_data datasets.MNIST(rootdata,trainTrue,downloadTru…

CRMEB標準版PC掃碼登錄配置教程(PHP版)

需要在開放平臺創建網站應用 微信開放平臺地址&#xff1a;https://open.weixin.qq.com/ 1、注冊網站應用 2、填寫信息&#xff0c;網站地址填寫前臺訪問的域名就行 3、復制開放平臺AppId和開放平臺AppSecret 4、粘貼到后臺應用配置的PC站點配置里

AmazeVault 核心功能分析,認證、安全和關鍵的功能

系列文章目錄 Amazevault 是一款專注于本地安全的桌面密碼管理器 AmazeVault 核心功能分析&#xff0c;認證、安全和關鍵的功能 AmazeVault 快速開始&#xff0c;打造個人專屬桌面密碼管理器 文章目錄系列文章目錄前言一、認證系統核心組件圖形解鎖實現圖形鎖控件 (PatternLoc…

Coze用戶賬號設置修改用戶昵稱-后端源碼

前言 本文將深入分析Coze Studio項目的用戶昵稱修改功能后端實現&#xff0c;通過源碼解讀來理解整個昵稱更新流程的架構設計和技術實現。用戶昵稱修改作為用戶個人信息管理系統的重要組成部分&#xff0c;主要負責處理用戶顯示名稱的更新和管理。 昵稱修改功能相對簡單但不失重…

基于WebTransport(底層QUIC)實現視頻傳輸(HTML+JavaScript)

工作目錄和基本操作見博客《基于HTTP3的WebTransport實踐》&#xff0c;在此僅展示服務器端和客戶端代碼。 服務器端 import { readFile } from "node:fs/promises"; import { createServer } from "node:https"; import {Server} from "socket.io&qu…

Git 怎么倉庫遷移?error: remote origin already exists.怎么解決

1. 確認本地已經有完整的 舊 倉庫你本地應該有舊的項目&#xff0c;并且能看到 .git 文件夾。如果沒有&#xff0c;可以先從舊倉庫克隆下來&#xff1a;git clone 舊倉庫git地址 cd 舊代碼目錄比如&#xff1a;git clone https://gitee.com/star-information/esflow-pro-api.gi…

【語法】【C+V】本身常用圖表類型用法快查【CSDN不支持,VSCODE可用】

文章目錄Mermaid 簡介Mermaid 由三部分組成Mermaid 的使用方法復雜圖表結構的技巧餅圖簡介餅圖語法餅圖示例雷達圖簡介雷達圖語法雷達圖語法細節標題軸曲線選項雷達圖示例時間線簡介時間線語法時間線示例樹形圖簡介樹形圖語法樹形圖示例數據包圖簡介數據包圖語法1&#xff1a;數…

Anaconda下載安裝教程(附Anaconda安裝包)

Anaconda下載安裝教程&#xff08;附Anaconda安裝包&#xff09;獲取&#xff1a;python開發工具包丨夸克網盤-資源免費下載 有位小粉絲剛剛入門python&#xff0c;問我怎么安裝Anaconda&#xff0c;于是我幫他找了一個詳細的Anaconda安裝教程和安裝包。 Anaconda其實是一個p…

那我現在有3個輸入 9層神經元 每層神經元數為 3 9 3 5 6 2 3 9 8 請給出我所有的權重矩陣

問題1 那我現在有3個輸入 9層神經元 每層神經元數為 3 9 3 5 6 2 3 9 8 請給出我所有的權重矩陣 明白&#xff0c;我們來系統地列出你的 9層全連接網絡 的權重矩陣。1?? 網絡結構 輸入層&#xff1a;3 個神經元隱藏層/輸出層&#xff1a;9 層神經元數分別為 [3,9,3,5,6,2,3,9…

廣東省省考備考(第八十七天8.26)——判斷推理(聽課后強化訓練)

判斷推理&#xff1a;定義判斷 錯題解析 第一步&#xff1a;找出定義關鍵詞。 “農村中各項經濟活動及由此產生的經濟關系”、“同農業有直接或間接的關系”。 第二步&#xff1a;逐一分析選項。 A項&#xff1a;該項指出具體的夏糧產量和增量&#xff0c;其中生產糧食屬于種植…

讀取 STM32H5 Data Flash 觸發 NMI 的問題解析 LAT1544

關鍵字&#xff1a;STM32H5, data flash&#xff0c; high-cycle data, NMI問題描述客戶反饋&#xff0c;使用 STM32H563 的 data flash(high-cycle data flash)&#xff0c;在還沒有寫入任何數據之前去讀取 data flash, 會觸發 hardfault 異常。1. 問題分析我們嘗試在 NUCLEO-…

學云計算還是網絡,選哪個好?

云計算工程師和網絡工程師&#xff0c;都是IT界香餑餑&#xff0c;但方向差很大&#xff01;選錯路后悔3年&#xff01;今天極限二選一&#xff0c;幫你徹底搞懂工作職責 網絡工程師&#xff1a;網絡世界的交警工程師&#xff01;主要管物理網絡和邏輯連接。負責設計、搭建、維…

Matlab使用——開發上位機APP,通過串口顯示來自單片機的電壓電流曲線,實現光伏I-V特性監測的設計

預覽此處的測試數據的采集頻率和曲線變化是通過更換電阻來測試的&#xff0c;所以電壓電流曲線顯示并不是很平滑&#xff0c;圖中可以看到每一個采集點的數值。這個設計是福州大學第三十期SRTP的一個校級的項目&#xff0c;打算通過分布式的在線掃描電路低成本的單片機&#xf…