当前位置: 首页 > news >正文

设计模式:原型模式(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.dtcms.com/a/349787.html

相关文章:

  • 使用 HandlerMethodReturnValueHandler 在SpringBoot项目 实现 RESTful API 返回值自动封装,简化开发
  • 数据结构青铜到王者第三话---ArrayList与顺序表(2)
  • 零知开源——基于STM32F103RBT6和ADXL335实现SG90舵机姿态控制系统
  • three.js+WebGL踩坑经验合集(9.1):polygonOffsetUnits工作原理大揭秘
  • 【数据结构】LeetCode160.相交链表 138.随即链表复制 牛客——链表回文问题
  • [SC]SystemC动态进程概述及案例
  • LinkedIn 自动消息发送工具
  • 网络编程——TCP、UDP
  • 人工智能(AI)与网络安全
  • 【Linux】协议的本质
  • 一键脚本:自动安装 Nginx + Certbot + HTTPS(Let‘s Encrypt)
  • QT-QSS样式表
  • 面试:计算机网络
  • 《输赢》电视剧总结学习
  • 数据结构:红黑树(Red-Black Tree)
  • 电商秒杀场景下,深挖JVM内存泄漏与多线程死锁的解决方案
  • Python3.14安装包下载与保姆级图文安装教程!!
  • PyTorch实战(1)——深度学习概述
  • 【动态规划】309. 买卖股票的最佳时机含冷冻期及动态规划模板
  • webpack文件指纹:hash、chunkhash与contenthash详解
  • 基于 OpenCV 与 Mediapipe 的二头肌弯举追踪器构建指南:从环境搭建到实时计数的完整实现
  • 【CV】图像基本操作——①图像的IO操作
  • 系统架构设计师-计算机系统存储管理-页式、段氏、段页式模拟题
  • [系统架构设计师]专业英语(二十二)
  • Python爬虫第四课:selenium自动化
  • Qwt7.0-打造更美观高效的Qt开源绘图控件库
  • macbook国内源安装rust
  • leetcode LCR 012.寻找数组的中心下标
  • 如何在 Jenkins 中安装 Master 和 Slave 节点以优化 CI/CD 流程
  • init.environ.rc详解