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

原型模式

缘起

某天,小明的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公司

总结

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

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

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

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

相关文章

【云备份|| 日志 day6】文件业务处理模块

云备份day6 业务处理 业务处理 云备份项目中 ,业务处理模块是针对客户端的业务请求进行处理,并最终给与响应。而整个过程中包含以下要实现的功能: 借助网络通信模块httplib库搭建http服务器与客户端进行网络通信针对收到的请求进行对应的业…

IDEA重新choose source

大概现状是这样:之前有个工程,依赖了别的模块基础包,但当时并没有依赖包的源码工程,因此,通过鼠标左键点进去,看到的是jar包里的class文件,注释什么的都去掉了的,不好看。后面有这个…

采用示波器显示扭矩传感器模拟信号

扭矩传感器输出的信号波形通常是模拟电压信号,可以通过示波器等仪器进行分析。扭矩传感器的输出信号波形通常有两种类型:正弦波和方波。 应变片传感器扭矩测量采用应变电测技术。在弹性轴上粘贴应变计组成测量电桥,当弹性轴受扭矩产生微小变…

Oracle(16)Managing Privileges

目录 一、基础知识 1、Managing Privileges管理权限 2、System Privileges 系统特权 3、System Privileges : Example系统权限:示例 4、Who Can Grant or Revoke? 谁可以授予或撤销权限? 5、The PUBLIC 6、SYSDBA and SYSOPER 7、Revoke with A…

分类预测 | Matlab实现PSO-LSTM粒子群算法优化长短期记忆神经网络的数据多输入分类预测

分类预测 | Matlab实现PSO-LSTM粒子群算法优化长短期记忆神经网络的数据多输入分类预测 目录 分类预测 | Matlab实现PSO-LSTM粒子群算法优化长短期记忆神经网络的数据多输入分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现PSO-LSTM粒子群算法优化长短…

Llama2通过llama.cpp模型量化 WindowsLinux本地部署

Llama2通过llama.cpp模型量化 Windows&Linux本地部署 什么是LLaMA 1 and 2 LLaMA,它是一组基础语言模型,参数范围从7B到65B。在数万亿的tokens上训练的模型,并表明可以专门使用公开可用的数据集来训练最先进的模型,而无需求…

KCC@广州与 TiDB 社区联手—广州开源盛宴

10月21日,KCC广州与 TiDB 社区联手,在海珠区保利中悦广场 29 楼召开了一次难忘的开源盛宴。这不仅仅是 KCC广州的又一次线下见面,更代表着与 TiDB 社区及广州技术社区的首次深度合作。 活动的策划与组织由 KCC广州负责人 - 惠世冀、PingCAP 的…

Ocelot:.NET开源API网关提供路由管理、服务发现、鉴权限流等功能

随着微服务的兴起,API网关越来越常见。API网关是连接应用程序和用户之间的桥梁,就像一个交通指挥员,负责处理所有进出应用的数据和请求,确保安全、高效、有序地流通。 今天给大家推荐一个.NET开源API网关。 01 项目简介 Ocelot…

用Powershell实现:删除所有不是与.json文件重名的.jpg文件

# 指定要搜索的目录路径 $directoryPath "C:\path\to\your\directory"# 获取该目录下的所有.jpg和.json文件 $jpgFiles Get-ChildItem -Path $directoryPath -Filter *.jpg $jsonFiles Get-ChildItem -Path $directoryPath -Filter *.json | Select-Object -Expan…

海外媒体发稿:彭博社发稿宣传中,5种精准营销方式

在如今的信息发生爆炸时期,营销方式多种多样,但是充分体现精准营销并针对不同用户群体的需求并非易事。下面我们就根据彭博社发稿营销推广为例子,给大家介绍怎样根据不同用户人群方案策划5种精准营销方式。 1.界定总体目标用户人群在制订精准…

CSS注入的四种实现方式

目录 CSS注入窃取标签属性数据 简单的一个实验: 解决hidden 方法1:jsnode.js实现 侧信道攻击 方法2:对比波兰研究院的方案 使用兄弟选择器 方法3:jswebsocket实现CSS注入 实验实现: 方法4:window…

数据分析实战 | 泊松回归——航班数据分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据准备 七、模型训练 八、模型评价 一、数据及分析对象 CSV文件:o-ring-erosion-only.csv 数据集链接:https://download.csdn.net/download/m0_7…

蓝桥杯算法竞赛第一周题型总结

本专栏内容为:蓝桥杯学习专栏,用于记录蓝桥杯的学习经验分享与总结。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:C 🚚代码仓库:小小unicorn的代码仓库🚚 🌹&#x1f33…

CH11_重构API

将查询函数和修改函数分离(Separate Query from Modifier) function getTotalOutstandingAndSendBill() {const result customer.invoices.reduce((total, each) > each.amount total, 0);sendBill();return result; }function totalOutstanding() …

SparkAi创作系统ChatGPT网站源码+详细搭建部署教程+AI绘画系统+支持GPT4.0+Midjourney绘画

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统,支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

「题解」反转链表 返回中间节点

文章目录 🍉题目1:反转链表🍉解析🍌解法一:创建一个新链表🍌解法二:直接操作原链表 🍉题目2:返回中间节点🍌解法一:快慢指针🍌解法二&…

工作量证明是解决拜占庭将军问题的唯一办法

号外:教链内参11.10《以太坊反攻》 文 | Oleg Andreev. 2014.5.23. 原标题:Proof That Proof-of-Work is the Only Solution to the Byzantine Generals Problem (本文是)回复Vlad_Roberto的话:“不,&#…

视频剪辑助手:轻松实现视频随机分割并提取音频保存

随着社交媒体和视频平台的日益普及,视频制作和分享已成为人们日常生活的一部分。无论是分享个人生活,还是展示才艺,或是推广产品,视频都是一个非常有效的工具。但是,视频制作往往涉及到大量的视频剪辑工作,…

算法导论6:摊还分析,显式与隐式

P258 摊还分析概念 聚合分析,利用它,我们证明对于n,一个n个操作的序列最坏情况下的花费的总时间为T(n),因此,在最坏情况下,每个操作的平均代价(摊还代价)为T(n)/n 举了例子来形容这…

模板初阶 C++

目录 泛型编程 函数模板 概念 格式 原理 函数模板的实例化 类模板 格式 类模板的实例化 泛型编程 当我们要实现一个交换函数,我们可以利用函数重载实现,但是有几个不好的地方 1.函数重载仅仅是类型不同,代码复用率较低,只…