05创建型设计模式——原型模式

news2024/9/23 13:28:38

一、原型模式简介

        原型模式(Prototype Pattern)模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例。使用原型模式创建的实例,具有与原型一样的数据。

1)由原型对象自身创建目标对象。换句话说,对象创建这一动作发自原型对象本身。

2)目标对象是原型对象的一个克隆(clone)。也就是说,通过原型模式创建的对象,不仅与原型对象具有相同的结构,还与原型对象具有相同的值。

原型模式具有浅克隆和深克隆之分。***深浅克隆的原型模式各有各的优势。

  • 浅克隆:复制对象的所有属性,但对于引用类型属性,仅复制引用。这会使得新对象与原始对象共享引用类型的内存空间。
  • 深克隆:复制对象的所有属性,即使是引用类型,也会创建新的实体,并复制指向这些实体的引用。这样新对象就与原始对象完全独立了。
原型模式的结构图

二、原型模式的用处

原型模式适用于需要多个一模一样的复杂对象,让其具有自我复制功能,统一一套接口。

 原型模式说白了它允许对象复制现有的对象,而不是每次都通过外部new关键字来创建新的对象。这种模式有助于减少对象的创建时间,特别是当对象初始化的成本较高时。原型模式的关键在于它使用一个原型对象来创建新的实例,而不是通过直接生成它们。

原型模式优点:

  1. 对象初始化成本较高,可以避免通过复制现有对象来减少创建时间。
  2. 避免编写复杂的工厂方法来生成各种对象。
  3. 当你想支持对象的深克隆或浅克隆时。

原型模式注意点:

  • 当原型及其后代需要支持克隆行为时,这种方法非常有效。
  • 如果没有对象的克隆能力,或者你的领域不支持“克隆”,原型模式可能不合适。
  • 使用原型模式时要确保能够处理循环引用的情况。

三、原型模式的设计方法

浅克隆的原型模式

        背景:假设我们有一个电子邮件系统,其中每封邮件都包含一个附件。当我们想要复制一封邮件时,我们可能不需要复制附件的实际内容,而只需要复制邮件的其他信息和对附件的引用。这种情况下,浅克隆是非常合适的选择。

shallow_Prototype.cpp
#include <iostream>
#include <cstring>

//附件
class Attachment {
private:
    std::string fileName;

public:
    Attachment(const std::string& name) : fileName(name) {}

    std::string getFileName() const {
        return fileName;
    }

     // 返回 fileName 的地址
    const std::string* getFileNameAddress() const {
        return &fileName;
    }
    
    Attachment* clone() const {
        return new Attachment(*this);
    }
};

//邮件
class Email {
public:
    Email(const std::string& sender, const std::string& recipient, const std::string& body, Attachment* attachment)
        : sender(sender), recipient(recipient), body(body), attachment(attachment) {}

    Email(const Email& other)
        : sender(other.sender), recipient(other.recipient), body(other.body), attachment(other.attachment) {}

    ~Email() {
        // 注意:这里没有删除附件,因为我们假设多个邮件共享同一个附件
        // 如果实现深拷贝,需要在此处删除附件
    }

    Email* clone() const {
        return new Email(*this);
    }

    void print() const {
        std::cout << "Sender: " << sender << std::endl;
        std::cout << "Recipient: " << recipient << std::endl;
        std::cout << "Body: " << body << std::endl;
        std::cout << "Attachment: " << (attachment ? attachment->getFileName() : "None") << std::endl;
    }
    
    Attachment* getAttachment() const {
    return attachment;
}

private:
    std::string sender;
    std::string recipient;
    std::string body;
    Attachment* attachment;
};

//模拟接口
void doWorking() {
    // 创建附件对象
    Attachment* attachment = new Attachment("document.pdf");

    // 创建邮件对象
    Email originalEmail("alice@example.com", "bob@example.com", "Hi Baby!", attachment);

    // 克隆邮件对象
    Email* clonedEmail = originalEmail.clone();

    // 打印原始邮件和克隆邮件的信息
    std::cout << "Original Email:" << std::endl;
    originalEmail.print();

    std::cout << std::endl << "Cloned Email:" << std::endl;
    clonedEmail->print();

    // 检查附件对象是否被共享(共享说明是浅克隆)
    std::cout << std::endl << "原始附件: " << originalEmail.getAttachment()->getFileName() << " 原始附件地址: " << originalEmail.getAttachment()->getFileNameAddress() << std::endl;
    std::cout << "深克隆附件: " << clonedEmail->getAttachment()->getFileName() << " 深克隆附件地址: " << clonedEmail->getAttachment()->getFileNameAddress() << std::endl;

    // 清理资源
    delete clonedEmail;
    return ;
}

int main() {
	
	//调用
	doWorking();
	return 0;
}

运行效果 

深克隆的原型模式
deep_Prototype.cpp
#include <iostream>
#include <cstring>

//附件
class Attachment {
private:
    std::string fileName;

public:
    Attachment(const std::string& name) : fileName(name) {}

    std::string getFileName() const {
        return fileName;
    }
    
     // 返回 fileName 的地址
    const std::string* getFileNameAddress() const {
        return &fileName;
    }

    Attachment* clone() const {
        return new Attachment(*this);
    }
};

//邮件
class Email {
public:
    Email(const std::string& sender, const std::string& recipient, const std::string& body, Attachment* attachment)
        : sender(sender), recipient(recipient), body(body), attachment(attachment ? attachment->clone():nullptr) {}

    Email(const Email& other)
        : sender(other.sender), recipient(other.recipient), body(other.body), attachment(other.attachment ? other.attachment->clone():nullptr) {}

    ~Email() {
        delete attachment;// 删除附件,避免内存泄漏
    }

    Email* clone() const {
        return new Email(*this);
    }

    void print() const {
        std::cout << "Sender: " << sender << std::endl;
        std::cout << "Recipient: " << recipient << std::endl;
        std::cout << "Body: " << body << std::endl;
        std::cout << "Attachment: " << (attachment ? attachment->getFileName() : "None") << std::endl;
    }
    
    Attachment* getAttachment() const {
    return attachment;
}

private:
    std::string sender;
    std::string recipient;
    std::string body;
    Attachment* attachment;
};

//模拟接口
void doWorking() {
    // 创建附件对象
    Attachment* attachment = new Attachment("document.pdf");

    // 创建邮件对象
    Email originalEmail("alice@example.com", "bob@example.com", "Hi Baby!", attachment);

    // 克隆邮件对象
    Email* clonedEmail = originalEmail.clone();

    // 打印原始邮件和克隆邮件的信息
    std::cout << "Original Email:" << std::endl;
    originalEmail.print();

    std::cout << std::endl << "Cloned Email:" << std::endl;
    clonedEmail->print();

    std::cout << std::endl << "原始附件: " << originalEmail.getAttachment()->getFileName() << " 原始附件地址: " << originalEmail.getAttachment()->getFileNameAddress() << std::endl;
    std::cout << "深克隆附件: " << clonedEmail->getAttachment()->getFileName() << " 深克隆附件地址: " << clonedEmail->getAttachment()->getFileNameAddress() << std::endl;

    // 清理资源
    delete clonedEmail;
    delete attachment;
    return ;
}

int main() {
	
	//调用
	doWorking();
	return 0;
}

运行效果

四、总结

原型模式的深拷贝和浅拷贝技术其实就是利用了指针的特性,指针本身具有指向的作用,当指针指向了堆区没有任何方法去拷贝或析构该堆区的数据,就造成了多个指针指向同一个堆区空间或多次析构的问题。

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

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

相关文章

python基础语法 010 类和对象-3 方法

1.3 方法 属性表示是一个类当中的成员或类的特征&#xff0c;而方法是&#xff1f;&#xff1f; 方法&#xff1a;表示类、对象的行为&#xff0c;方法本质上是函数&#xff0c;是一个特殊的函数 属性名称一般为名词&#xff0c;方法名称一般为动词 1.3.1 方法 VS 属性 1、…

24/8/17算法笔记 DDPG算法

深度确定性策略梯度&#xff08;DDPG&#xff09;算法是一种用于解决连续动作空间强化学习问题的算法。它结合了确定性策略梯度&#xff08;DPG&#xff09;和深度学习技术的优点&#xff0c;通过Actor-Critic框架进行策略和价值函数的近似表示。DDPG算法的关键组成部分包括经验…

【RAG综述】北京大学检索增强技术综述

RAG for AIGC ​ 图 1 描述了一个典型的 RAG 过程。给定一个输入查询&#xff0c;检索器识别相关的数据源&#xff0c;检索到的信息与生成器交互以改进生成过程。根据检索结果如何增强生成&#xff0c;有几种基础范式&#xff08;简称基础&#xff09;&#xff1a;它们可以作为…

STM32的蜂鸣器

蜂鸣器分为有源蜂鸣器和无源蜂鸣器。 有源蜂鸣器&#xff1a;内部有震荡源&#xff0c;只要通电即可自动发出固定频率的声音。&#xff08;频率固定无 法控制音色&#xff09; 。 无源蜂鸣器&#xff1a;内部无震荡源&#xff0c;需要外部脉冲信号驱动发声&#xff0c;声音频…

《机器学习》 线性回归 一元、多元 推导 No.3

一、什么是线性回归 线性回归是一种用于预测连续数值的机器学习算法。它基于输入特征与目标变量之间的线性关系建立了一个线性模型。线性回归的目标是找到最佳拟合直线&#xff0c;以最小化预测值与实际值之间的误差。这个线性模型可以用来进行预测和推断。 线性回归的模型可以…

SpringBoot Profile多环境配置及配置优先级

【SpringBoot学习笔记 三】Profile多环境配置及配置优先级_profiles队列中的优先值-CSDN博客 Profile激活方式 但是我们发现一个问题&#xff0c;就是每次切换环境还需要去配置里指定&#xff0c;然后通过修改dev为test或prod来切换项目环境 , 这样做的话每次切换环境都要重新改…

前端面试——如何判断对象和数组

给你一个值&#xff0c;如何判断其是对象还是数组&#xff1f;&#xff1f;&#xff1f; 我们先给出数据 var lists [1,2,3,4,5]var objs {length:5 } 我们分别尝试如下五种方法 console.log((✘)使用length,lists.length,objs.length); console.log((✔)使用isArray,Arr…

【已成功EI检索】第三届机电一体化技术与航空航天工程国际学术会议(ICMTAE 2023)

重要信息 大会官网&#xff1a;www.icmtae.org 大会时间&#xff1a;2023年9月15-17日 大会地点&#xff1a;中国-江西南昌理工学院&#xff08;南昌市青山湖区经济技术开发区英雄大道901号&#xff09; 接受/拒稿通知&#xff1a;投稿后1周内 收录检索&#xff1a;EI 和 …

Vulkan 学习(4)---- Vulkan 逻辑设备

目录 Vulkan Logical Device OverView逻辑设备创建VkDeviceQueueCreateInfoDeviceExtension获取DeviceQueue参考代码 Vulkan Logical Device OverView 在 Vulkan 中&#xff0c;逻辑设备(Logical Device)是与物理设备(Physical Device)交互的接口,它抽象了对特定GPU(物理设备)…

CDD数据库文件制作(八)——服务配置(0x85)

目录 1.子功能创建2.会话切换配置/安全等级配置2.1.根据诊断调查表进行信息提取2.2.会话转换配置/安全等级配置3.寻址方式信息提取/禁止肯定响应位(SPRMIB)信息3.1.寻址方式/禁止肯定响应位(SPRMIB)配置4.否定响应码信息提取4.1.否定响应码配置按照诊断调查表中对0x85服务的…

PX30 Android8.1适配AIC8800 wifi

wifi驱动生成ko文件 生成后 通过wpa_supplicant加载参数 external/wpa_supplicant_8/wpa_supplicant/main.c int main(int argc, char *argv[]) {int ret -1;char module_type[20]{0};wpa_printf(MSG_INFO,"argc %d\n",argc);if(argc 2) {if (wifi_type[0] 0) …

【MySQL】数据库基础(表的操作)

目录 一、创建表 二、查看表结构 三、修改表 3.1 添加新列 3.2 修改列属性 3.3 删除列属性 3.4 修改表名 3.5 向表中插入 3.6 修改列名 四、删除表 一、创建表 语法&#xff1a; CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) …

docker容器安全加固参考建议——筑梦之路

这里主要是rootless的方案。 在以 root 用户身份运行 Docker 会带来一些潜在的危害和安全风险&#xff0c;这些风险包括&#xff1a; 容器逃逸&#xff1a;如果一个容器以 root 权限运行&#xff0c;并且它包含了漏洞或者被攻击者滥用&#xff0c;那么攻击者可能会成功逃出容器…

车载camera avm框图

一、关键词介绍: POC: power on coax LVDS: Low-Voltage Differential Signaling GMSL:Gigabit Multimedia Serial Link AVM: Around View Monitor Serdes:DeSerializer、Serializer DVP:Interface with ISP and Sensor: DVP(Digital Video Port) 二、车载camera avm…

书籍推荐:大数据之路 阿里巴巴大数据实践

书籍推荐&#xff1a;大数据之路 阿里巴巴大数据实践 这本书侧重于理论知识&#xff0c;并结合了阿里大数据发展的过程&#xff0c;将知识总结起来。总的来所&#xff0c;书中的有些章节个人感觉非常不错&#xff0c;比如&#xff1a;数据仓库建模&#xff1b;但是大部分章节都…

性能优化理论篇 | 如何保证数据安全落盘,5分钟彻底弄懂 一次write中的各种缓冲区 !

性能优化系列目录&#xff1a; 性能优化理论篇 | 彻底弄懂系统平均负载 性能优化理论篇 | swap area是个什么东西 性能优化理论篇 | Cache VS Buffer&#xff0c;傻傻分不清 &#xff1f; 在很多IO场景中&#xff0c;我们经常需要确保数据已经安全的写到磁盘上&#xff0c;以便…

xss之DOM破坏

文章目录 DOM破坏漏洞的复现https://xss.pwnfunction.com/基于bp学院DOM破坏漏洞复现思路分析实现 常见的xss触发的标签没有过滤的情况存在过滤的情况 DOM破坏 DOM破坏就是⼀种将 HTML 代码注⼊⻚⾯中以操纵 DOM 并最终更改⻚⾯上 JavaScript ⾏为的技术。 在⽆法直接 XSS的情…

Linux·权限与工具-make

1. Makefile/makefile工具 首先展示一下&#xff0c;makefile工具如何使用。我们先写一个C语言程序 然后我们建立一个Makefile/makefile文件&#xff0c;m大小写均可。我们在文件中写入这样两行 wq保存退出后&#xff0c;我们使用 make 命令 可以看到生成了可执行程序&#xff…

无人机模拟训练室技术详解

无人机模拟训练室作为现代无人机技术培训的重要组成部分&#xff0c;集成了高精度模拟技术、先进的数据处理能力及高度交互的操作界面&#xff0c;为无人机操作员提供了一个安全、高效、接近实战的训练环境。以下是对无人机模拟训练室技术的详细解析&#xff0c;涵盖系统基础概…

为TI的 AM355移植uboot和linux内核

一、uboot移植 在移植之前要先对uboot的源码结构有一定熟悉 1.uboot源码顶层目录下各源码文件夹的作用 2.编译后生成的uboot.xxx 各文件后缀含义 关于以上两点社区已经有很多前辈总结的很详细&#xff0c;这里不做赘述。 对于uboot源码分析韦东山老师b站上有免费的课程&#x…