《设计模式的艺术》笔记 - 原型模式

介绍

        使用原型实例指定创建对象的种类,并且通过克隆这些原型创建新的对象。原型模式是一种对象创建型模式。

实现

myclass.h

//
// Created by yuwp on 2024/1/12.
//#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H#include <iostream>class Prototype {
public:void setId(uint64_t id);uint64_t getId();virtual Prototype *clone() = 0;private:uint64_t m_id;
};class ConcretePrototype : public Prototype {
public:Prototype *clone() override;
};#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

//
// Created by yuwp on 2024/1/12.
//#include "myclass.h"void Prototype::setId(uint64_t id) {m_id = id;
}uint64_t Prototype::getId() {return m_id;
}Prototype* ConcretePrototype::clone() {ConcretePrototype *prototype = new ConcretePrototype();prototype->setId(this->getId());return prototype;
}

main.cpp

#include <iostream>
#include <mutex>
#include "myclass.h"int main() {Prototype *obj1 = new ConcretePrototype();std::cout << "obj1: " << std::hex << obj1 << ", id: " << obj1->getId() << std::endl;auto obj2 = obj1->clone();std::cout << "obj2: " << std::hex << obj2 << ", id: " << obj2->getId() << std::endl;delete obj1;delete obj2;return 0;
}

总结

        优点:

        1. 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率。

        2. 扩展性较好。由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程,而将具体原型类写在配置文件中,增加或减少具体原型类对原有系统都没有任何影响。

        3. 原型模式提供了简化的创建结构。工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式就不需要这样。原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品。

        4. 可以使用深克隆的方式保存对象的状态。使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用,例如恢复到某一历史状态,可辅助实现撤销操作。

        缺点:

        1. 需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部。当对已有的类进行改造时,需要修改源代码,违背了开闭原则。

        2. 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦。

        适用场景:

        1. 创建新对象成本较大(例如初始化需要占用较长的时间,占用太多的CPU资源或网络资源)。新的对象可以通过原型模式对已有对象进行复制来获得,如果是相似对象,则可以对其成员变量稍作修改。

        2. 如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占用内存较少时,可以使用原型模式配合备忘录模式(本书第21章介绍)来实现。

        3. 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态。通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。

练习

myclass.h

//
// Created by yuwp on 2024/1/12.
//#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H#include <iostream>class Address {
public:std::string m_name;uint32_t m_id;
};class Object {
public:virtual Object *deepClone() = 0;virtual Object *clone() = 0;
};class Customer : public Object {
public:Customer() {}Customer(Address *addr);Address *getAddress();void setAddress(Address *addr);Object *deepClone() override;Object *clone() override;private:Address *m_addr;
};#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

//
// Created by yuwp on 2024/1/12.
//#include "myclass.h"Customer::Customer(Address *addr) {m_addr = addr;
}Address* Customer::getAddress() {return m_addr;
}void Customer::setAddress(Address *addr) {m_addr = addr;
}Object* Customer::clone() {Customer *customer = new Customer();customer->setAddress(m_addr);return customer;
}Object* Customer::deepClone() {Customer *customer = new Customer();Address *address = new Address();address->m_id = m_addr->m_id;address->m_name = m_addr->m_name;customer->setAddress(address);return customer;
}

main.cpp

#include <iostream>
#include <mutex>
#include "myclass.h"int main() {Address *addr = new Address();addr->m_id = 1;addr->m_name = "abc";Object *obj1 = new Customer(addr);auto obj2 = obj1->clone();auto obj3 = obj1->deepClone();std::cout << "obj1: " << std::hex << obj1 << ", addr = " << std::hex << dynamic_cast<Customer *>(obj1)->getAddress() << ", id = " << dynamic_cast<Customer *>(obj1)->getAddress()->m_id << ", name = " << dynamic_cast<Customer *>(obj1)->getAddress()->m_name << std::endl;std::cout << "obj2: " << std::hex << obj2 << ", addr = " << std::hex << dynamic_cast<Customer *>(obj2)->getAddress() << ", id = " << dynamic_cast<Customer *>(obj2)->getAddress()->m_id << ", name = " << dynamic_cast<Customer *>(obj2)->getAddress()->m_name << std::endl;std::cout << "obj3: " << std::hex << obj3 << ", addr = " << std::hex << dynamic_cast<Customer *>(obj3)->getAddress() << ", id = " << dynamic_cast<Customer *>(obj3)->getAddress()->m_id << ", name = " << dynamic_cast<Customer *>(obj3)->getAddress()->m_name << std::endl;return 0;
}

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

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

相关文章

Day32- 贪心算法part06

一、单调递增的数字 题目一&#xff1a;738. 单调递增的数字 738. 单调递增的数字 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。 给定一个整数 n &#xff0c;返回 小于或等于 n 的最大数字&#xff0c;且数字呈 单调递…

k8s---ingress对外服务(ingress-controller)

ingress 概念 k8s的对外服务&#xff0c;ingress service作用现在两个方面&#xff1a; 1、集群内部&#xff1a;不断跟踪的变化&#xff0c;更新endpoint中的pod对象&#xff0c;基于pod的ip地址不断变化的一种服务发现机制。 2、集群外部&#xff1a;类似于负载均衡器&a…

进阶Docker3:Dokerfile构建镜像

目录 Dockerfile 构建基础镜像 基本机构 命令&#xff1a; 命令解释&#xff1a; 准备工作 创建镜像 上传镜像 Dockerfile Dockerfile 是一个文本格式的配置文件&#xff0c; 用户可以使用 Dockerfile 来快速创建自定义的镜像&#xff0c;另外&#xff0c;使 用Docke…

Docker 安装 MySQ

Docker 安装 MySQL MySQL 是世界上最受欢迎的开源数据库。凭借其可靠性、易用性和性能&#xff0c;MySQL 已成为 Web 应用程序的数据库优先选择。 1、查看可用的 MySQL 版本 访问 MySQL 镜像库地址&#xff1a;https://hub.docker.com/_/mysql?tabtags 。 可以通过 Sort b…

使用docker部署RStudio容器并结合内网穿透实现公网访问

文章目录 前言1. 安装RStudio Server2. 本地访问3. Linux 安装cpolar4. 配置RStudio server公网访问地址5. 公网远程访问RStudio6. 固定RStudio公网地址 前言 RStudio Server 使你能够在 Linux 服务器上运行你所熟悉和喜爱的 RStudio IDE&#xff0c;并通过 Web 浏览器进行访问…

旅游项目day04

1. JWT有效期 封装用户登录对象&#xff0c; 在指定时间过期 2. 有些接口需要登录&#xff1f;有些不需要登录&#xff1f; 后端如何知道a需要登录&#xff0c;b不需要登录&#xff1f; 注解。 3. 目的地 一个区域下面包含多个目的地 数据库表&#xff1a; 1. 区域表 2.…

交互设计:提升用户动机

之前给大家介绍了交互设计的底层模型——最新版福格行为模型。 模型告诉我们想让用户进行某个行为有3个步骤&#xff0c;第一个步骤是检查有没有&#xff08;合理的&#xff09;行为提示&#xff0c;我把它翻译成能否吸引用户注意&#xff0c;感兴趣的同学可以查看《交互设计之…

Linux--进程控制

进程终止 进程终止是指一个正在运行的进程结束其执行并释放占用的系统资源的过程。进程可以通过以下几种方式终止&#xff1a; 正常终止&#xff1a;进程完成了它的任务&#xff0c;或者遇到了终止条件&#xff0c;例如调用了exit()函数或主函数执行完毕。 异常终止&#xff1…

代码随想录刷题题Day36

刷题的第三十六天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C Day36 任务 ● 123.买卖股票的最佳时机III ● 188.买卖股票的最佳时机IV 1 买卖股票的最佳时机III 123.买卖股票的最佳时机III …

Maven--pom.xml文件详解

1.pom简介 pom指的是project object model&#xff0c;又叫项目对象模型。Maven的pom文件是一个XML文件&#xff0c;用于描述项目的各种属性、依赖和构建信息&#xff0c;包括项目的名称、版本、许可证、作者、描述、依赖关系、构建过程、插件等。总的来说&#xff0c;POM文件…

计算机网络——数据链路层(1)

一、概述 在计算机网络中&#xff0c;数据链路层承担着点对点通信的任务&#xff0c;用于跨物理层在网段节点之间参数数据。它在网络分层中处于物理层之上&#xff0c;网路层之下。 在链路层的讨论中&#xff0c;我们将看到两种截然不同类型的链路层信道。第一种类型是广播信道…

The Blocks Problem

本题是一道模拟题&#xff0c;但个人感觉挺有意思的&#xff08;思路很明确&#xff0c;但是WA了好几发才过&#xff09;&#xff0c;因此来讲一讲思路。 题面 题面PDF 样例输入 10 move 9 onto 1 move 8 over 1 move 7 over 1 move 6 over 1 pile 8 over 6 pile 8 over 5…

设计模式——1_5 享元(Flyweight)

今人不见古时月&#xff0c;今月曾经照古人 ——李白 文章目录 定义图纸一个例子&#xff1a;可以复用的样式表绘制表格降本增效&#xff1f;第一步&#xff0c;先分析 变化和不变的地方第二步&#xff0c;把变化和不变的地方拆开来第三步&#xff1a;有没有办法共享这些内容完…

Three.js 学习笔记之模型(学习中1.18更新)

文章目录 模型 几何体 材质模型点模型Points - 用于显示点线模型Line | LineLoop | LineSegments网格模型mesh - 三角形 几何体BufferGeometry缓冲类型几何体BufferGeometry - 基类创建几何体的方式BufferAttribute Types定义顶点法线 geometry.attributes.normal BufferGeom…

您的孩子上课总是开小差?注意力不集中?来看看这个专注力提升利器!

我们会发现&#xff0c;有些时候孩子在上课以及写作业&#xff0c;虽然手里握着笔&#xff0c;但是思绪已经“飘到外太空去了”&#xff0c;无法集中注意力&#xff1b;考试的过程中&#xff0c;更是马虎大意&#xff0c;不经过思考就直接作答&#xff0c;或者重复犯简单的错误…

debian 12 安装 浏览器 Epiphany

Epiphany 什么epiphany-browser epiphany-browser 是&#xff1a; Epiphany 是一款简单而强大的 GNOME 网络浏览器&#xff0c;针对 非技术用户。它的原则是简单和标准 合规。 简单性是通过精心设计的用户界面和依赖来实现的 在用于执行外部任务&#xff08;如阅读 电子邮件…

创建一个自定义的VSCode插件项目

创建一个自定义的VSCode插件项目需要以下步骤&#xff1a; 安装Node.js和npm&#xff1a;VSCode插件是用TypeScript或JavaScript编写的&#xff0c;所以你需要安装Node.js和npm。你可以在Node.js官方网站下载并安装。 安装Yeoman和VS Code Extension Generator&#xff1a;Ye…

opengauss-高斯数据库的安装部署及MySQL数据迁移实战.

目录 介绍 下载安装包 安装 1.设置SEMMNI 2.新建用户和用户组 3.下载安装包解压 4.安装数据库 5.修改配置 6.重启服务 数据库使用 gsql命令和常用sql 1.使用omm用户连接数据库-本地登陆无需输入密码&#xff1a; 2.查看用户信息 3.删除数据库 4.创建用户 5.创建…

【银行测试】银行项目,信贷/贷款业务测试+常问面试(二)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 银行测试-信贷&am…

RabbitMQ常见问题之延迟消息

文章目录 一、死信交换机二、TTL1. Queue指定死信交换机并设置TTL2. 消息设置TTL 三、延迟队列1. SpringAMQP创建延迟队列2. 设置消息延迟3. 测试 一、死信交换机 当一个队列中的消息满足下列情况之一时&#xff0c;可以成为死信&#xff08;dead letter&#xff09;&#xff…