原型设计模式的学习

哪位大佬帮我看看关于“原型设计模式”的问题

写作原因:

我需要了解原型模式,但网上的说法是:通过一个clone方法来创建对象。然而,这并没有解答关于“效率”的问题:

以下是以怪物游戏和深拷贝为例来说明的:

  1. 为什么使用这种模式来创建大量怪物效率会更高?难道不是都通过new来创建的吗?自定义的clone方法难道不是在底层调用new,与直接调用new相比效率有显著差异吗?
  2. 无论使用何种方法,每个怪物的大小都是一样的,为什么克隆拷贝会比新建实例更快?而且并没有使用多线程或多进程。

总体来说一个句话概况:为什么克隆拷贝会比新建实例更快?


于是我让GPT创建了一个 原型设计模式 的测试案例

#include <iostream>
#include <string>
#include <chrono>class ComplexObject {
private:std::string data;
public:ComplexObject(const std::string& d) : data(d) {// 模拟耗时的初始化操作std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "ComplexObject constructed with data: " << data << std::endl;}ComplexObject(const ComplexObject& other) : data(other.data) {std::cout << "ComplexObject copied with data: " << data << std::endl;}void setData(const std::string& newData) {data = newData;}void printData() {std::cout << "Data: " << data << std::endl;}
};class ObjectPrototype {
private:ComplexObject* prototype;
public:ObjectPrototype(ComplexObject* obj) : prototype(obj) {}ComplexObject* clone() {// 通过复制构造函数来创建新对象return new ComplexObject(*prototype);}
};int main() {// 创建原型对象ComplexObject* prototype = new ComplexObject("Prototype Data");// 使用原型对象创建新对象ObjectPrototype* objPrototype = new ObjectPrototype(prototype);// 复制原型对象来创建新对象ComplexObject* newObj1 = objPrototype->clone();ComplexObject* newObj2 = objPrototype->clone();newObj1->printData();newObj2->printData();delete prototype;delete newObj1;delete newObj2;delete objPrototype;return 0;
}

代码分析

ComplexObject 的 拷贝构造速度>构造函数速度 ,因为构造函数中有个延时sleep的操作。所以,原型设计模式的克隆是通过拷贝构造函数实现,而拷贝构造速度>构造函数速度 ,所以 clone > new 。这确实没问题。

代码总结

GPT认为:速度快需要 拷贝构造速度>构造函数速度 才能加速,否则无法加速。

仍然无法加速的情况

上述代码没有考虑到深拷贝的情况。在深拷贝时候,拷贝构造速度构造函数速度可能差不多,就无法加速了。比如下面的代码

案例:深拷贝 + 原型设计模式对比实验

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <vector>constexpr auto N = 10000;
constexpr auto NUMBER_OF_People = 1000 ;class ComplexObject {
private:long long  data;std::vector<long long> * m_pNumbers = new std::vector<long long>;
public:ComplexObject(const long long& d) : data(d) {// 用创建大数组模拟耗时的初始化操作for (int i = 0; i < N; i ++){m_pNumbers->push_back(i);}(*m_pNumbers)[0] = data;std::cout << "ComplexObject constructed with data: " << data << std::endl;}ComplexObject(const ComplexObject& other, long long id) : data(other.data) {// 用深拷贝大数组模拟耗时的初始化操作for (int i = 0; i < N; i++){m_pNumbers->push_back((*(other.m_pNumbers))[i]);}(*m_pNumbers)[0] = id;std::cout << "ComplexObject copied with data: " << (*m_pNumbers)[0] << std::endl;}void printData() {std::cout << "Data: " << (*m_pNumbers)[0] << std::endl;}
};class ObjectPrototype {
private:ComplexObject* prototype;
public:ObjectPrototype(ComplexObject* obj) : prototype(obj) {}ComplexObject* clone(int id) {// 通过复制构造函数来创建新对象return new ComplexObject(*prototype,id);}
};// 使用原型设计模式的情况
int main1() {std::cout << "Test prototype begin" << std::endl << std::endl;// 创建原型对象ComplexObject* prototype = new ComplexObject(1);// 使用原型对象创建新对象ObjectPrototype* objPrototype = new ObjectPrototype(prototype);std::vector< ComplexObject*> g_vecPeople;// 复制原型对象来创建新对象auto start = std::chrono::high_resolution_clock::now();for (int i = 2; i < NUMBER_OF_People; i++){ComplexObject* newObj  = objPrototype->clone(i);g_vecPeople.push_back(newObj);}auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);double durationInSeconds = duration.count() / 1000000.0; // 转换为秒std::cout << "Function execution time: " << durationInSeconds << " seconds" << std::endl;for (std::vector< ComplexObject*>::iterator it = g_vecPeople.begin(); it != g_vecPeople.end(); it++){if (*it){delete* it;*it = nullptr;}}g_vecPeople.clear();delete prototype;delete objPrototype;return 0;
}// 一般的情况
int main() {std::cout << "Test STD begin" << std::endl << std::endl;// 创建原型对象ComplexObject* prototype = new ComplexObject(1);std::vector< ComplexObject*> g_vecPeople;// 复制原型对象来创建新对象auto start = std::chrono::high_resolution_clock::now();for (int i = 2; i < NUMBER_OF_People; i++){ComplexObject* newObj = new ComplexObject(i);g_vecPeople.push_back(newObj);}auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);double durationInSeconds = duration.count() / 1000000.0; // 转换为秒std::cout << "Function execution time: " << durationInSeconds << " seconds" << std::endl;for (std::vector< ComplexObject*>::iterator it = g_vecPeople.begin(); it != g_vecPeople.end(); it++){if (*it){delete* it;*it = nullptr;}}g_vecPeople.clear();return 0;
}

代码分析

上述代码构造了一种 拷贝构造速度==构造函数速度 的情况,发现没有实现加速。

得到一个奇怪的结论:深拷贝情况下,创立多个对象,似乎原型设计模式无法加速。


更新一下GPT的回答

问:

如果ComplexObject 类的 拷贝构造函数的 和 构造函数速度相同,那使用原型设计模式创建多个对象还有加速的效果吗?

答:

原型设计模式的主要目的是通过复制现有对象来创建新对象,从而避免了使用常规的构造函数来初始化新对象的开销。如果复制构造函数的速度与常规构造函数相同,那么在性能方面可能不会有太大的加速效果。
然而,即使复制构造函数的速度与常规构造函数相同,使用原型设计模式仍然可以带来一些优势:
减少初始化时间:尽管构造函数的速度相同,但使用原型模式可以避免一些初始化步骤,因为新对象可以直接从现有对象复制而来,而不需要重新执行构造函数中的初始化操作。
避免重复的计算和初始化:如果对象的创建涉及到复杂的计算或初始化过程,使用原型模式可以避免重复执行这些计算和初始化步骤,因为新对象可以直接从现有对象复制而来。
灵活性:使用原型模式可以更灵活地创建对象,因为可以根据现有对象的状态来创建新对象,而不受构造函数的限制。
总的来说,尽管在速度方面可能没有显著的加速效果,但使用原型模式仍然可以提高代码的性能和灵活性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/797192.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 常用指令及其理论知识

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;http://t.csdnimg.cn/Tvyou 欢迎各位指教&#xff01;&#xff01;&#xff01; 目录 一、理论知识 二、基础指令 1、ls指令&#xff08;列出该目录下的所有子目录和文件&#xff09; 语法&#xff1a; …

论文阅读——Sat2Vid

Sat2Vid: Street-view Panoramic Video Synthesis from a Single Satellite Image 提出了一种新颖的方法&#xff0c;用于从单个卫星图像和摄像机轨迹合成时间和几何一致的街景全景视频。 即根据单个卫星图像和给定的观看位置尽可能真实地、尽可能一致地合成街景全景视频序列。…

Docker中Mysql报 mbind: Operation not permitted

问题 我们在docker中安装的mysql运行时报 mbind: Operation not permitted mbind: Operation not permitted mbind: Operation not permitted mbind: Operation not permitted mbind: Operation not permitted mbind: Operation not permitted原因 这是Docker的Seccomp安全限…

[leetcode] 25. K 个一组翻转链表

给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内部的值…

MySQL(目录)

作者&#xff1a;码农出击 链接&#xff1a;https://www.zhihu.com/question/632989513/answer/3312494291 来源&#xff1a;知乎 著作权归作者所有。 MySQL数据库&#xff08;7天~15天&#xff09; 1、数据存储引擎&#xff1a;InnoDB、myISAM、Memory 2、数据库索引类型及原…

最好用的安卓按钮(3)

属性解释 按钮文字 app:text“床前明月光” 按钮文字颜色 app:textColor“color/color_white” 按钮文字大小 app:textSize“22sp” 按钮背景颜色 app:color_normal“color/color_accent” 0x2 单独设置每个圆角 效果 代码 <top.androidman.SuperButton android:layo…

替换空格(替换特定字符)

&#x1f600;前言 在字符串处理中&#xff0c;经常会遇到需要替换特定字符的情况。本文将介绍一道经典的字符串替换问题&#xff1a;将字符串中的空格替换成 “%20”。我们将探讨一种高效的解决方法&#xff0c;通过倒序遍历字符串来实现原地替换&#xff0c;避免额外空间的开…

也说说Sybase ASE中的空间膨胀及应对方案

前言 直观来讲,数据库是典型的以空间换时间的思路去提高数据检索的效率。我们先把数据“入”进去,组织好,建好索引,都为了什么?相当大一部分只不过是为了最终能快速得到查询的结果。当然这又引发了好多子项,比如,怎么“入”得快而又不发生冲突,怎么在相对少的资源的情…

OpenCV中的模块:三维重建-SFM(2)

接上一篇文章,本篇将介绍SFM模块在windows平台上的编译。与Ubuntu下的过程类似,主要过程也是依赖库的下载、编译及安装,不同点是:与Ubuntu直接安装不同,windows下我们将对库的依赖关系更加清晰。 1. 依赖库的编译 打开相应库的最外层CMakeLists.txt所在的目录,库的编译过…

机器学习_PySpark-3.0.3文本特征提取(TF-IDF)流程

机器学习_PySpark-3.0.3文本特征提取(TF-IDF)流程 本例中 Tokenizer 是用于分词的模块。 本例中 HashingTF().tranform() 函数把词哈希成特征向量, 返回结果是 Vectors.sparse() 类型的。 本例中 IDF 类用于计算给定文档集合的反文档频率, 是一个词普遍重要性的度量 (即: 一…

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(八)- 向量整数算术指令

1. 引言 以下是《riscv-v-spec-1.0.pdf》文档的关键内容&#xff1a; 这是一份关于向量扩展的详细技术文档&#xff0c;内容覆盖了向量指令集的多个关键方面&#xff0c;如向量寄存器状态映射、向量指令格式、向量加载和存储操作、向量内存对齐约束、向量内存一致性模型、向量…

Linux 内核的构建块:深入探索 C 结构体的应用

Linux 内核的构建块&#xff1a;深入探索 C 结构体的应用 Linux 内核&#xff0c;作为操作系统的中心和基础&#xff0c;承担着调度处理器、管理内存、处理输入/输出&#xff08;I/O&#xff09;等各种底层任务。要实现这些复杂的功能&#xff0c;内核的编写借助了 C 语言强大…

SAP FICO接口-OA-调取SAP供应商明细接口(应付预付明细)开发说明书(包括测试样例、程序代码仅作参考,不保证一定可以运行)

需求说明: 根据OA查询条件查询ZVACDOCAZVACDOCA-BUKRS=查询公司代码; ZVACDOCA- LIFNR=查询供应商代码; ZVACDOCA-BELNR=查询凭证编号; ZVACDOCA-GJAHR=查询会计年度; ZVACDOCA-AWKEY=查询采购发票号*; ZVACDOCA-BLART≠W* ZVACDOCA-AUGBL=空 ZVACDOCA- XREVERSED…

ShrewSoft VPN无法连接.报错failed to attach to key daemon的解决方案

今天突然发现使用的ShrewSoft VPN 软件来连接公司网络。但是连接过程中&#xff0c;报错 “Fail to attach to key daemon” 解决步骤&#xff1a; 1. 重启电脑&#xff0c;可以解决90%问题。 2. 可能和ShrewSoft 相关的服务没有启动有关。 于是检查服务状态。 2.1 按Wind…

中国省级基础设施网络完善进程:2000-2022年数据分析与展望(无缺失值)

01、数据介绍 基础设施&#xff0c;作为为社会生产和居民生活提供公共服务的物质工程设施&#xff0c;是一个用于保证社会经济活动正常进行的公共服务系统。它不仅包括交通设施&#xff0c;还涵盖了邮电、供水供电、商业服务、科研与技术服务、园林绿化、环境保护、文化教育、…

富格林:明示虚假现象确保安全

富格林认为&#xff0c;当下的金融市场&#xff0c;投资者进行理财时都会特别关注盈利效率高的产品&#xff0c;而近来兴起的现货黄金则以此优势吸引着大批人关注。不过现货黄金市场相对于其他投资市场来说&#xff0c;会复杂一点不乏会蕴含着虚假现象。因此要确保我们的交易安…

Linux诊断机器故障工具—dmesg命令

在 Linux 系统中&#xff0c;经常会遇到各种各样的故障和问题&#xff0c;这些问题可能会导致系统性能下降、服务异常甚至系统崩溃。而 dmesg 命令是一个强大的工具&#xff0c;可以帮助我们诊断和解决这些故障。我们将介绍如何使用 dmesg 命令来分析和解决 Linux 系统中的常见…

基于单片机分舱式电开水炉位控制系统

**单片机设计介绍&#xff0c;基于单片机分舱式电开水炉位控制系统 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机分舱式电开水炉位控制系统概要主要涉及通过单片机对电开水炉的各个舱位进行精确控制&#xff0c;实现水位、温度…

Impala Daemon无法启动问题记录(25000端口被占用)

前言&#xff1a;集群主节点根目录内存快爆了&#xff0c;开始清理主节点内存重启组件&#xff0c;发现Kerberos认证的角色用户都过期了&#xff0c;又重新生成了一下角色&#xff0c;在启动impala组件过程中&#xff0c;其中一个Impala Daemon组件启动失败。 集群版本&#xf…

【热门话题】Stable Diffusion:本地部署教程

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Stable Diffusion&#xff1a;本地部署教程一、引言二、环境准备1. 硬件配置2. …