文章目录

  • 原型模式简介
  • 原型模式结构
  • 关于克隆方法:浅拷贝/深拷贝
  • 原型模式代码实例
    • 定义原型类和克隆方法
    • 客户端使用代码示例
      • 示例一:浅拷贝
    • 示例二:深拷贝
  • 原型模式总结
    • 开闭原则

代码仓库

原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

定义看起来有点绕口,不妨简单的理解为:原型模式就是用来克隆对象的。

举个例子,比如有一天,周杰伦到奶茶店点了一份不加冰的原味奶茶,你说我是周杰伦的忠实粉,我也要一份跟周杰伦一样的。
在这里插入图片描述

即便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…