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

C++设计模式——Prototype Pattern原型模式

一,原型模式的定义

原型模式是一种创建型设计模式,它允许通过克隆已有对象来创建新对象,从而无需调用显式的实例化过程。

原型模式的设计,使得它可以创建一个与原型对象相同或类似的新对象,同时又可以减少对象实例化操作产生的性能开销,使得创建对象的操作更加便捷,它减少了大量不必要的重复工作,并提高了系统性能。

当创建对象的操作比较复杂和耗时的时候,原型模式则提供了一个更加高效和简单的创建对象的模式,它可以更加快速的创建对象的副本,且不需要依赖对象的某些实例化步骤,它避免了使用传统的new关键字创建对象实例时的复杂构造过程。

原型模式的主要缺点则是原型对象必须预先存在于系统中,并且需要预先进行注册。此时,如果有大量的原型对象需要被创建,并且每个原型对象都需要进行自定义,维护和管理这些原型对象可能会变得很复杂。

原型模式在现实生活中的抽象实例:

图形绘制:假设我们需要绘制不同形状的图形,可以定义一个图形类作为原型,然后通过克隆该原型对象来创建具体的图形对象。

陶艺制作:先制作一个陶艺原型作为参考,然后通过复制或克隆原型来制作出多个相似的陶艺品。

服装设计:设计师预先设计一套成衣样板,然后通过复制或克隆样板来制作出多件相似或不同款式的服装。

二,原型模式的结构

原型模式主要包含以下组件:

1.抽象原型(Prototype):定义克隆方法的接口,具体原型类通过实现这些方法来提供其自身的副本。

2.具体原型(ConcretePrototype):包含抽象原型类的具体实现,它会提供一个复制自身的方法,该方法将创建并返回一个对象副本。

3.客户端(Client):客户端使用原型类来创建新对象的副本,它会先获取原型对象,并使用原型对象的克隆方法来创建新的对象实例。

组件之间的工作步骤如下:

1.客户端通过实例化具体原型类,并调用其克隆方法来创建一个原型对象。

2.原型对象调用自身的克隆方法,将自身复制一份,返回一个克隆的对象。

3.客户端获取到克隆对象后,可以根据自身的业务需求对其进行进一步的修改和使用。

对应UML类图:

三,原型模式代码样例

Demo1:

#include <iostream>
#include <string>//定义原型基类
class Prototype {
public:virtual ~Prototype() {}virtual Prototype* clone() const = 0;virtual void print() const = 0;
};//定义具体原型类
class ConcretePrototype : public Prototype{
private:std::string name;
public:ConcretePrototype(const std::string& name) : name(name) {}Prototype* clone() const override {return new ConcretePrototype(*this);}void print() const override {std::cout << "Prototype: " << name << std::endl;}
};int main() {//创建原型对象ConcretePrototype prototype("Original");//使用原型对象创建新对象Prototype* clone = prototype.clone();clone->print();//释放内存delete clone;return 0;
}

运行结果:

Prototype: Original

Demo2:

#include <iostream>
#include <string>class Prototype {
public:virtual ~Prototype() {}virtual Prototype* clone() const = 0;virtual void info() const = 0;
};class ConcretePrototypeA: public Prototype {
public:ConcretePrototypeA(int id, std::string name): m_id(id), m_name(name) {}Prototype* clone() const override {return new ConcretePrototypeA(*this);}void info() const override {std::cout << "ConcretePrototypeA: id = "<< m_id << ", name = " << m_name <<  std::endl;}
private:int m_id;std::string m_name;
};class ConcretePrototypeB: public Prototype {
public:ConcretePrototypeB(std::string description): m_description(description) {}Prototype* clone() const override {return new ConcretePrototypeB(*this);}void info() const override {std::cout << "ConcretePrototypeB: description = " << m_description <<  std::endl;}
private:std::string m_description;
};int main() {ConcretePrototypeA* prototypeA = new ConcretePrototypeA(1, "First");Prototype* cloneA = prototypeA->clone();cloneA->info();ConcretePrototypeB* prototypeB = new ConcretePrototypeB("This is a prototype");Prototype* cloneB = prototypeB->clone();cloneB->info();delete prototypeA;delete cloneA;delete prototypeB;delete cloneB;return 0;
}

运行结果:

ConcretePrototypeA: id = 1, name = First
ConcretePrototypeB: description = This is a prototype

四,原型模式的应用场景

图形用户界面:创建可定制的控件,如Windows的对话框,设计一个原型控件,让用户根据需求选择属性进行定制。

文本编辑器开发:支持“剪切”、“复制”、“粘贴”的功能,使用已存在的文档作为复制和创建新文档的原型。

数据库开发:将数据库的某个状态视为原型,当需要创建新的数据库版本时,可以直接从这个原型复制。

配置工具开发:基于原型模式帮助快速生成配置对象,而无需每次都新建一个空的配置。

Web应用程序:让用户可以在原型基础上添加、修改字段,动态生成表单元素。

五,原型模式的优缺点

原型模式的优点:

简化了对象的创建过程,使得代码更加简洁且易于维护。

提高了动态创建对象和销毁对象的效率。

封装和隐藏了创建对象的细节。

减少了对构造函数的直接调用,提高了代码的性能。

支持灵活的定制具体对象的属性和方法。

原型模式的缺点:

需要实现克隆对象的接口。

需要配合深拷贝或浅拷贝来使用,可能会导致引用对象的复制。

有的原型模式基于递归的方式来克隆对象,可能会引起堆栈溢出的问题。

针对大型对象的复制,会占用特别多的内存。

六,代码实战

Demo1:基于智能指针封装的原型模式:

#include <memory>
#include <iostream>class Prototype {
public:virtual std::unique_ptr<Prototype> clone() const = 0;void printValue() const {std::cout << "Origin Value." << std::endl;}
};class ConcretePrototype : public Prototype {
private:int value;
public:ConcretePrototype(int v) : value(v) {}std::unique_ptr<Prototype> clone() const override {return std::make_unique<ConcretePrototype>(value);}void printValue() const {std::cout << "Value: " << value << std::endl;}
};int main() {auto prototype = std::make_unique<ConcretePrototype>(5);auto clonedPrototype = prototype->clone();prototype->printValue();clonedPrototype->printValue();return 0;
}

运行结果:

Value: 5
Origin Value.

Demo2:基于工厂的方式管理各种原型

#include <iostream>
#include <string>
#include <map>class Prototype {
public:int data;std::string name;Prototype(int data, const std::string& name) : data(data), name(name) {}virtual Prototype* clone() {return new Prototype(*this);}
};class PrototypeFactory {
private:std::map<std::string, Prototype*> prototypes;
public:PrototypeFactory() {prototypes["original"] = new Prototype(40, "Original");prototypes["copy"] = new Prototype(100, "Copy");}Prototype* create(const std::string& type) {return prototypes[type]->clone();}
};int main() {PrototypeFactory factory;Prototype* original = factory.create("original");Prototype* copy = factory.create("copy");std::cout << "Original: data="<< original->data<< ", name="<< original->name << std::endl;std::cout << "Copy: data="<< copy->data<< ", name="<< copy->name << std::endl;delete original;delete copy;return 0;
}

运行结果:

Original: data=40, name=Original
Copy: data=100, name=Copy

七,参考阅读

https://softwarepatterns.com/cpp/prototype-software-pattern-cpp-example

https://www.geeksforgeeks.org/prototype-design-pattern/

https://www.tutorialspoint.com/design_pattern/prototype_pattern.html

https://sourcemaking.com/design_patterns/prototype

https://softwareparticles.com/design-patterns-prototype/

相关文章:

C++设计模式——Prototype Pattern原型模式

一&#xff0c;原型模式的定义 原型模式是一种创建型设计模式&#xff0c;它允许通过克隆已有对象来创建新对象&#xff0c;从而无需调用显式的实例化过程。 原型模式的设计&#xff0c;使得它可以创建一个与原型对象相同或类似的新对象&#xff0c;同时又可以减少对象实例化…...

Vue3 : ref 与 reactive

目录 一.ref 二.reactive 三.ref与reactive的区别 四.总结 一.ref 在 Vue 3 中&#xff0c;ref 是一个用于创建可读写且支持数据跟踪的响应式引用对象。它主要用于在组件内部创建响应式数据&#xff0c;这些数据可以是基本类型&#xff08;如 number、string、boolean&…...

html实现好看的多种风格手风琴折叠菜单效果合集(附源码)

文章目录 1.设计来源1.1 风格1 -图文结合手风琴1.2 风格2 - 纯图片手风琴1.3 风格3 - 导航手风琴1.4 风格4 - 双图手风琴1.5 风格5 - 综合手风琴1.6 风格6 - 简描手风琴1.7 风格7 - 功能手风琴1.8 风格8 - 全屏手风琴1.9 风格9 - 全屏灵活手风琴 2.效果和源码2.1 动态效果2.2 源…...

Nacos分布式配置中心

分布式配置的优势&#xff1a; 不需要重新发布我们的应用 新建父工程&#xff1a;【将它作为跟 所以要把父工程里面的src删掉】 新建子模块&#xff1a; 新建bootstrap.properties&#xff1a; 在使用Nacos作为配置中心时&#xff0c;推荐在bootstrap.properties中配置Nacos相…...

C# WinForm 中 DataGridView 实现单元格cell 能进编辑状态但是不能修改单元格的效果

在Windows Forms&#xff08;WinForms&#xff09;开发中&#xff0c;DataGridView 控件是一个功能强大的组件&#xff0c; 用于显示和管理表格数据。无论是展示大量数据&#xff0c;还是实现交互式的数据操作&#xff0c; DataGridView 都能提供多样的功能支持&#xff0c;比如…...

GANs-生成对抗网络

参考&#xff1a; https://mp.weixin.qq.com/s?__bizMjM5ODIwNjEzNQ&mid2649887403&idx3&snf61fc0e238ffbc56a7f1249b93c20690&chksmbfa0f632460e035f00be6cc6eb09637d91614e4c31da9ff47077ca468caad1ee27d08c04ca32&scene27 https://cloud.tencent.com…...

e冒泡排序---复杂度O(X^2)

排序原理: 1.比较相邻的元素。如果前一个元素比后一个元素大&#xff0c;就交换这两个元素的位置。 2.对每一对相邻元素做同样的工作,从开始第一对元素到结尾的最后一对元素。最终最后位置的元素就是最大值, public class 冒泡排序 {public static void main(String[] args) {I…...

C语言--结构体(学习笔记)

内容借鉴于b站杜远超官方频道&#xff08;C语言结构体详解【干货】&#xff09; 首先C语言中定义变量格式为“数据类型 变量名”&#xff0c;如int a; float b;等等。 那么结构体则是将多个变量&#xff08;数据类型 变量名&#xff09;结合在一起的一种新的数据类型&…...

Vue项目中实现用户登录后跳回原地址

本地存储 在 Vue 3 中&#xff0c;你可以使用 Vue Router 和 sessionStorage 或 localStorage 来实现用户登录后跳回原来的页面。以下是一种常见的实现方式&#xff1a; 在用户登录之前&#xff0c;记录当前页面的路由路径&#xff1a; 在需要登录的页面组件中&#xff0c;在…...

【Google Chrome Windows 64 version及 WebDriver 版本】

最近升级到最新版本Chrome后发现页面居然显示错乱实在无语, 打算退回原来的版本, 又发现官方只提供最新的版本下载, 为了解决这个问题所有收集了Chrome历史版本的下载地址分享给大家. Google Chrome Windows version 64 位 VersionSize下载地址Date104.0.5112.10282.76 MBhtt…...

[ffmpeg] 音视频编码

本文主要梳理 ffmpeg 中音视频编码的常用函数 API调用 常用 API const AVCodec *avcodec_find_encoder(enum AVCodecID id); AVCodecContext *avcodec_alloc_context3(const AVCodec *codec); void avcodec_free_context(AVCodecContext **avctx); int avcodec_open2(AVCode…...

springboot+redis+缓存

整合 添加依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 连接redis&#xff0c;配置yml文件 主机 端口号 数据库是哪一个 密码 配置类 p…...

关于http的206状态码和416状态码的意义、断点续传以及CORS使用Access-Control-Allow-Origin来允许跨域请求

一、关于http的206状态码和416状态码的意义及断点续传 HTTP 2xx范围内的状态码表明客户端发送的请求已经被服务器接受并且被成功处理了,HTTP/1.1 206状态码表示客户端通过发送范围请求头Range抓取到了资源的部分数据&#xff0c;一般用来解决大文件下载问题&#xff0c;一般CDN…...

SOMEIP_ETS_114: SD_Entries_Length_wrong_combined

测试目的&#xff1a; 验证DUT能够拒绝一个包含两个正确条目但条目数组长度不正确的SubscribeEventgroup消息&#xff0c;并以SubscribeEventgroupNAck作为响应。 描述 本测试用例旨在确保DUT遵循SOME/IP协议&#xff0c;当接收到一个条目数组长度与实际条目数量不匹配的Sub…...

SQL:DATEDIFF函数

DATEDIFF函数是用于计算两个日期之间的时间间隔的函数&#xff0c;它在不同的编程语言和数据库系统中都有广泛的应用。以下是对DATEDIFF函数的详细解析&#xff1a; 一、函数用途 DATEDIFF函数的主要用途是计算两个日期之间的时间间隔&#xff0c;这个间隔可以是年、季度、月…...

MATLAB 可视化基础:绘图命令与应用

目录 1. 绘制子图1.1基本绘图命令1.2. 使用 subplot 函数1.3. 绘图类型 2.MATLAB 可视化进阶(以下代码均居于以上代码的数据定义上实现)2.1. 极坐标图2.3. 隐函数的绘制 3.总结 在数据分析和科学计算中&#xff0c;数据可视化是理解和解释结果的关键工具。今天&#xff0c;我将…...

掌握 Python 异常处理的实战技巧:从基础到高级应用20240918

掌握 Python 异常处理的实战技巧&#xff1a;从基础到高级应用 引言 在 Python 编程中&#xff0c;异常处理是保障代码稳健性和可靠性的关键要素之一。无论是在网络请求、资源访问&#xff0c;还是复杂的业务逻辑中&#xff0c;异常处理都不可或缺。本文将从 Python 异常的基…...

One API 部署与配置指南

技术文档&#xff1a;One API 部署与配置指南 概述 One API 是一个多功能的 API 管理平台&#xff0c;支持自定义设置、用户管理、多种登录注册方式、主题切换等。本文档提供了详细的部署和配置指南&#xff0c;帮助用户快速搭建和使用 One API。 部署 基于 Docker 部署 D…...

国密起步7:BouncyCastle使用SM4自定义格式加解密C#版

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 github源码指引的指引-CSDN博…...

Qt优秀开源项目之二十三:QSimpleUpdater

QSimpleUpdater是开源的自动升级模块&#xff0c;用于检测、下载和安装更新。 github地址&#xff1a;https://github.com/alex-spataru/QSimpleUpdater QSimpleUpdater目前Star不多&#xff08;911个&#xff09;&#xff0c;但已在很多开源项目看到其身影&#xff0c;比如Not…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...