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

设计模式之--原型模式(深浅拷贝)

原型模式

缘起

某天,小明的Leader找到小明:“小明啊,如果有个发简历的需求,就是有个简历的模板,然后打印很多份,要去一份一份展示出来,用编程怎么实现呢?”

小明一听,脑袋里就有了思路,二十分钟后给了一版代码

// 简历类
public class Resume {private String name;private String sex;private String age;private String timeArea;private String company;public Resume(String name) {this.name = name;}// 设置个人信息public void setPersonalInfo(String sex, String age) {this.sex = sex;this.age = age;}// 设置工作经历public void setWorkExperience(String timeArea, String company) {this.timeArea = timeArea;this.company = company;}// 展示简历public void display() {System.out.println(this.name + " " + this.sex + " " + this.age);System.out.println("工作经历 " + this.timeArea + " " + this.company);}
}

客户端代码

public static void main(String[] args) {Resume resume1 = new Resume("小明");resume1.setPersonalInfo("男", "22");resume1.setWorkExperience("2021-2023", "XX公司");Resume resume2 = new Resume("小明");resume2.setPersonalInfo("男", "22");resume2.setWorkExperience("2021-2023", "XX公司");Resume resume3 = new Resume("小明");resume1.setPersonalInfo("男", "22");resume1.setWorkExperience("2021-2023", "XX公司");resume1.display();resume2.display();resume3.display();}

Leader看后,说道:“挺好,这其实就是我当年手写简历时代的代码哈哈哈,三份简历需要实例化三次。你觉得这样会不会麻烦呢?如果二十份简历,你就要实例化二十次是不是;而且如果你写错了一个字,那你就要改20次,你可以这么写”

public class Test {public static void main(String[] args) {Resume resume1 = new Resume("小明");resume1.setPersonalInfo("男", "22");resume1.setWorkExperience("2021-2023", "XX公司");Resume resume2 = resume1;Resume resume3 = resume1;resume1.display();resume2.display();resume3.display();}
}

“其实就是传递引用对象,而不是传值,这样做就如同是在resume2、resume3纸上是空白的,而将resume1上的内容粘贴到了resume2、resume3上面,你还有没有其他的方式能实现呢?比如emmm,Clone克隆”。

原型模式

忙活了好一会儿,小明找到了一个相关的设计模式–原型模式。

原型模式(Prototype),用原型实例指定创建对象的种类,并且通过复制这些原型创建的对象。

在这里插入图片描述

原型模式其实就是从一个对象再创建另外一个可制定的对象,而且不需要知道任何的创建细节。

看下基本原型模式的代码。

  • 原型类
// 原型类
public abstract class Prototype implements Cloneable{private String id;public Prototype(String id) {this.id = id;}public String getId() {return id;}@Overrideprotected Object clone() {Object object = null;try {object = super.clone();} catch (CloneNotSupportedException e) {System.out.println("克隆异常");}return object;}
}
  • 具体原型类
public class ConcretePrototype extends Prototype {public ConcretePrototype(String id) {super(id);}
}
  • 客户端调用
ConcretePrototype p1 = new ConcretePrototype("123456");
System.out.println("原型ID:" + p1.getId());ConcretePrototype p2 = (ConcretePrototype) p1.clone();
System.out.println("克隆ID:" + p2.getId());

这样子只需要实例化一个对象,其他的类实例化时,只需要克隆这个对象即可。

对于Java而言,那个原型抽象类Prototype是用不到的,因为克隆实在是太常用了,所以Java提供了Cloneable接口,其中有一个唯一的方法就是clone(),我们只需要实现这个接口就可以完成原型模式了。

简历原型模式实现

小明二十分钟后,第二版代码出炉了。

// 简历类
public class Resume implements Cloneable{private String name;private String sex;private String age;private String timeArea;private String company;public Resume(String name) {this.name = name;}// 设置个人信息public void setPersonalInfo(String sex, String age) {this.sex = sex;this.age = age;}// 设置工作经历public void setWorkExperience(String timeArea, String company) {this.timeArea = timeArea;this.company = company;}// 展示简历public void display() {System.out.println(this.name + " " + this.age + " " + this.age);System.out.println("工作经历 " + this.timeArea + " " + this.company);}@Overrideprotected Resume clone() throws CloneNotSupportedException {return (Resume) super.clone();}
}
  • 客户端调用
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Resume resume1 = new Resume("小明");resume1.setPersonalInfo("男", "22");resume1.setWorkExperience("2021-2023", "XX公司");Resume resume2 = resume1.clone();Resume resume3 = resume1.clone();resume1.display();resume2.display();resume3.display();}
}
// 结果如下
小明 男 22
工作经历 2021-2023 XX公司
小明 男 22
工作经历 2021-2023 XX公司
小明 男 22
工作经历 2021-2023 XX公司

Leader看后点了点头,“一般在初始化的信息不发生变化的情况下,克隆就是最好的办法。这既隐藏了对象的创建细节,又对性能是大大的提高。不用重新初始化对象,而是动态获得对象运行时的状态。”

Leader接着又问道:“别高兴太早了,你知道这种clone有什么弊端吗,或者说是需要注意的点呢”

小明摇了摇头,Leader接着说:“你知道深浅拷贝吧,如果字段是值类型的,则对该字段逐位复制;如果是引用类型的则只复制引用,不复制引用的对象;因此,原始对象及其副本中的引用都是同一个对象”。

“你先把工作经历单独抽离出来,然后用简历类使用它们。”

小明不到十分钟,改完了。

  • 简历类
// 简历类
public class Resume implements Cloneable{private String name;private String sex;private String age;private WorkExperience work;public Resume(String name) {this.name = name;this.work = new WorkExperience(); // 实例化工作经历对象}// 设置个人信息public void setPersonalInfo(String sex, String age) {this.sex = sex;this.age = age;}// 设置工作经历public void setWorkExperience(String timeArea, String company) {this.work.setTimeArea(timeArea);this.work.setCompany(company);}// 展示简历public void display() {System.out.println(this.name + " " + this.sex + " " + this.age);System.out.println("工作经历 " + this.work.getTimeArea() + " " + this.work.getCompany());}@Overrideprotected Resume clone() throws CloneNotSupportedException {return (Resume) super.clone();}
}
  • 工作经历类
public class WorkExperience {private String timeArea;private String company;public String getTimeArea() {return timeArea;}public void setTimeArea(String timeArea) {this.timeArea = timeArea;}public String getCompany() {return company;}public void setCompany(String company) {this.company = company;}
}
  • 客户端
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Resume resume1 = new Resume("小明");resume1.setPersonalInfo("男", "22");resume1.setWorkExperience("2021-2023", "XX公司");Resume resume2 = resume1.clone();resume2.setWorkExperience("2001-2003", "ABC集团");Resume resume3 = resume1.clone();resume2.setWorkExperience("2005-2007", "ABC公司");resume1.display();resume2.display();resume3.display();}
}
// 执行结果如下
小明 男 22
工作经历 2005-2007 ABC公司
小明 男 22
工作经历 2005-2007 ABC公司
小明 男 22
工作经历 2005-2007 ABC公司

“看明白了吧,一个原型,两个副本它们的,workExperience对象全都是同一个引用,所以你改一个,其他的全都变了,这就是浅复制了。而我需要它们的workExperience对象全都是复制的对象,不能相同。”

简历深拷贝实现

“实现这个其实很简单,就是你的被引用对象,也去实现Cloneable接口,实现clone()方法,然后在引用类中将它们处理下就行了,快去查下相关资料,实现一下试试”。

小明半小时后,新的代码又出炉了。

  • WorkExperience工作经历类
public class WorkExperience implements Cloneable{private String timeArea;private String company;@Overrideprotected WorkExperience clone() throws CloneNotSupportedException {return (WorkExperience) super.clone();}.....
}
  • 简历类
// 简历类
public class Resume implements Cloneable{private String name;private String sex;private String age;private WorkExperience work;....@Overrideprotected Resume clone() throws CloneNotSupportedException {// 处理引用的对象Resume r = (Resume) super.clone();r.work = this.work.clone();return r;}
}

再来测试下。

小明 男 22
工作经历 2021-2023 XX公司
小明 男 22
工作经历 2005-2007 ABC公司
小明 男 22
工作经历 2021-2023 XX公司

总结

浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。

深复制:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

相关文章:

设计模式之--原型模式(深浅拷贝)

原型模式 缘起 某天,小明的Leader找到小明:“小明啊,如果有个发简历的需求,就是有个简历的模板,然后打印很多份,要去一份一份展示出来,用编程怎么实现呢?” 小明一听,脑袋里就有了…...

Linux服务器从零开始训练 RT-DETR 改进项目 (Ultralytics) 教程,改进RTDETR算法(包括使用训练、验证、推理教程)

手把手从零开始训练 RT-DETR 改进项目 (Ultralytics版本) 教程,改进RTDETR算法 本文以Linux服务器为例:从零开始使用Linux训练 RT-DETR 算法项目 《芒果剑指 RT-DETR 目标检测算法 改进》 适用于芒果专栏改进RT-DETR算法 文章目录 百度 RT-DETR 算法介绍改进网络代码汇总第…...

矩阵理论--矩阵分解

矩阵理论–矩阵分解 矩阵的三角分解、谱分解、最大秩分解、奇异值分解的操作步骤,以及相关说明。 1、QR分解 (1)非奇异方阵 方阵(非奇异):将方阵分解成酉矩阵左乘正线上三角,或者酉矩阵右乘…...

go语言相关bug

第一个bug itcastitcast:/home/jian/share/src/go-test/homeweb-client$ go mod tidy go: finding module for package github.com/micro/go-grpc go: found github.com/micro/go-grpc in github.com/micro/go-grpc v1.0.1 go: homeweb-client/handler importsgithub.com/micr…...

Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用

💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用 Spring Cloud OpenFeign是一个声明式的服务调用框架,基于Feign并整合了Ribbon和…...

租用服务器带宽类型应用

服务器带宽类型多样,以满足不同行业的需求。本文将介绍香港常见的服务器带宽类型及其应用领域。 1. 共享带宽 共享带宽是指多个用户共同使用同一台服务器的带宽资源。这种带宽类型适用于小型企业或个人网站,因为其成本较低。由于多个用户共享带宽资源&…...

SOLIDWORKS实用技巧之焊件轮廓应用

1.焊件轮廓库官方下载入口 焊件轮廓可以自制,也可以从软件中在线下载获取直接使用,如图1,联网状态按ctrl左键点击下载,解压后获得库文件。 图1 图2 2.库放置的位置和配置 从SOLIDWORKS2014版起,软件焊件轮廓库支持可…...

本地浏览器全局翻译 demo 以火狐firefox为例【免费-简单】

translateDemo 介绍使用说明简单到流泪 本地浏览器全局翻译 demo 以火狐firefox为例 1、安装插件 使用少量的 JavaScript 脚本,自由定义网页显示与运行方式。2、将上述脚本 追加到 插件中即可实现全局翻译;3、免费;参与贡献特技 translateDe…...

使用多线程处理List数据

最近遇到了一个业务场景&#xff0c;需要对List中的数据逐个发起http请求(List中的数据各自独立&#xff0c;对执行顺序无要求)&#xff0c;考虑到可以使用多线程加快处理速度。 封装了如下方法&#xff1a; /// <summary>/// 多线程处理数据-无返回值/// </summary&…...

Elasticsearch--Python使用、Django/Flask集成

一、Python使用 from elasticsearch import Elasticsearchobj Elasticsearch() # 创建索引&#xff08;Index&#xff09; result obj.indices.create(indexuser, body{"userid":1,username:lqz},ignore400) # print(result) # 删除索引 # result obj.indices.de…...

pyspark将数据多次插入表的时候报错

代码 报错信息 py4j.protocol.Py4JJavaError: An error occurred while calling o129.sql. : org.apache.spark.sql.catalyst.parser.ParseException: mismatched input INSERT expecting <EOF>(line 12, pos 0) 原因 插入语句结束后没有加&#xff1b;结尾 把两个&am…...

Qt绘制饼状图

必须在MainWindow.h头文件开头放 #include <QtCharts> //必须这么设置 创建chart&#xff1a; void MainWindow::iniPiewChart() { //饼图初始化QChart *chart new QChart();chart->setTitle(" Piechart演示");chart->setAnimationOptions(QChar…...

Vue3 setup函数

一、setup函数介绍 setup函数是Vue3中全新的一个配置项&#xff0c;值为一个函数&#xff0c;是所有 Composition API 中“表演的舞台”。 我们在Vue2中用到的所有数据、方法&#xff0c;都需要配置在setup中。 这是我们在Vue2中的写法&#xff1a; 这是我们在Vue3 setup中的…...

Django(三、数据的增删改查、Django生命周期流程图)

文章目录 一、 基于ORM进行的CURDuser_list&#xff1a;作为主页使用路由文件urls.py配置如下&#xff1a;add.html&#xff1a;用于新增用户的数据页add页面视图函数如下:edit.html&#xff1a;修改数据的页面那么来总结一下上序所操作所用到的内容。 导入已存在的表其方式有两…...

Linux 部署Sentinel控制台

Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 1.版本选择 SpringCloudAlibaba SpringClo…...

服务器如何下载百度网盘数据

百度网盘作为镜像 国外用户传数据到我们服务器比较慢,但是传输百度网盘速度还是可以的。 这样我们就可以将百度网盘作为一个文件中转站。 但Linux系统下使用百度网盘有些麻烦,虽然百度网盘也有Linux版本,但服务器没开启图形界面,使用的是命令行。这个时候就得感谢开发者Ho…...

POJ 3254 Corn Fields 状态压缩DP(铺砖问题)

一、题目大意 我们要在N * M的田地里种植玉米&#xff0c;有如下限制条件&#xff1a; 1、对已经种植了玉米的位置&#xff0c;它的四个相邻位置都无法继续种植玉米。 2、题目中有说一些块无论如何&#xff0c;都无法种植玉米。 求所有种植玉米的方案数&#xff08;不种植也…...

transformers安装避坑

1.4 下载rust编辑器 看到这里你肯定会疑惑了&#xff0c;我们不是要用python的吗&#xff1f; 这个我也不知道&#xff0c;你下了就对了&#xff0c;不然后面的transformers无法安装 因为是windows到官网选择推荐的下载方式https://www.rust-lang.org/tools/install。 执行文…...

牛客、赛码网OJ调试(全)

现在无论开发还是测试&#xff0c;面试的时候都需要考察代码能力。 从测试的职业发展来看&#xff0c;现在市场上对于纯功能测试的需求很少&#xff0c;招聘方均要求面试者一方面具备测试基础能力&#xff0c;也要求有点代码能力。 对于测试来说&#xff0c;除了测试开发&#…...

【CSS】全局声明引入自定义字体

以下用vue项目为例&#xff0c;其他的也是类似&#xff01; 在Vue.js中可以使用全局样式表来定义字体。通常&#xff0c;可以在项目中的主样式表中定义全局字体&#xff0c;然后确保该样式表在整个应用程序中被引入。 以下是一般的步骤&#xff1a; 在项目中创建一个全局样式…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

Redis数据倾斜问题解决

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

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...

webpack面试题

面试题&#xff1a;webpack介绍和简单使用 一、webpack&#xff08;模块化打包工具&#xff09;1. webpack是把项目当作一个整体&#xff0c;通过给定的一个主文件&#xff0c;webpack将从这个主文件开始找到你项目当中的所有依赖文件&#xff0c;使用loaders来处理它们&#x…...