【深入理解设计模式】原型设计模式

在这里插入图片描述

原型设计模式

原型设计模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制已有对象来创建新对象,而无需直接依赖它们的具体类。这种模式通常用于需要频繁创建相似对象的场景,以避免昂贵的创建操作或初始化过程。

概述

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

结构

原型模式包含如下角色:

  • 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • 访问类:使用具体原型类中的 clone() 方法来复制新的对象。

实现

原型模式的克隆分为浅克隆和深克隆。

(经典面试题)什么是深克隆和浅克隆
答:在计算机内存中,每个对象都有一个地址,这个地址指向对象在内存中存储的位置。当我们使用变量引用一个对象时,实际上是将该对象的地址赋值给变量。因此,如果我们将一个对象复制到另一个变量中,实际上是将对象的地址复制到了这个变量中。
<-------------------------------------------------------------------------------------------------------------------->
浅拷贝是指将一个对象复制到另一个变量中,但是只是复制对象的地址,而不是对象本身。也就是说,原始对象的复制对象实际上是共享同一个内存地址的。因此,如果我们修改了复制对象中的属性或元素,原始对象中对应的属性或元素也会被修改。
<-------------------------------------------------------------------------------------------------------------------->
深拷贝是指将一个对象及其所有子对象都复制到另一个变量中,也就是说,它会创建一个全新的对象,并将原始对象中的所有属性或元素都复制到新的对象中。因此,如果我们修改复制对象中的属性或元素,原始对象中对应的属性或元素不会受到影响。

浅克隆:
  1. Java中的Object类中提供了 clone() 方法来实现浅克隆。 Cloneable 接口是抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类。代码如下:
/*** @author OldGj * @version v1.0* @apiNote 具体原型类-原型模式*/
public class Realizetype implements Cloneable {public Realizetype() {System.out.println("原型创建");}@Overridepublic Realizetype clone() throws CloneNotSupportedException {System.out.println("原型克隆");return (Realizetype) super.clone();}
}
/*** @author OldGj * @version v1.0* @apiNote 测试类 - 测试原型模式克隆*/
public class Client {public static void main(String[] args) throws CloneNotSupportedException {Realizetype realizetype = new Realizetype();Realizetype cloned = realizetype.clone();System.out.println(cloned==realizetype); // false}
}
  1. 使用BeanUtils实现浅拷贝
    BeanUtils 是 Apache Commons BeanUtils 库中的一个类,它提供了一组用于操作 Java Bean 对象的工具方法。Java Bean 是一种符合特定约定的 Java 类,通常包含私有字段、公共 getter 和 setter 方法。BeanUtils 库可以用于在不直接访问对象字段的情况下操作 Bean 对象的属性。
/*** @author OldGj 2024/02/23* @version v1.0* @apiNote 使用BeanUtils实现浅克隆 - 用户类*/
public class User {private String name;private String password;private Address address;--- 省略get/set方法
}
/*** @author OldGj 2024/02/23* @version v1.0* @apiNote 使用BeanUtils实现浅拷贝 - 地址类*/
public class Address {private String province;private String city;--- 省略get/set方法
}
/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 测试类 - 测试原型模式克隆*/
public class Client {public static void main(String[] args) throws CloneNotSupportedException, InvocationTargetException, IllegalAccessException {User user = new User();user.setAddress(new Address("beijing","shanghai"));User user1 = new User();BeanUtils.copyProperties(user,user1);System.out.println(user == user1); // falseSystem.out.println(user.getAddress() == user1.getAddress()); // true : 浅拷贝}
}
深克隆:
  1. 实现Cloneable接口,重写clone();

在Objecta类中定义了一个clone方法,这个方法其实在不重写的情况下,其实也是浅拷贝的。

如果想要实现深拷贝,就需要重写clone方法,而想要重写clone方法,就必须实现Cloneable,否则会报Clone NotSupportedException异常。

/*** @author OldGj 2024/02/23* @version v1.0* @apiNote 重写clone方法实现深克隆- 地址类*/
public class Address {private String province;private String city;--- 省略get/set方法
}
/*** @author OldGj * @version v1.0* @apiNote 重写clone方法实现深克隆 - 用户类*/
public class User implements Cloneable{private String name;private String password;private Address address;@Overrideprotected Object clone() throws CloneNotSupportedException {User user = (User) super.clone();user.setAddress(new Address());return user;}--- 省略get/set方法
}
/*** @author OldGj * @version v1.0* @apiNote 测试类 - 测试原型模式克隆*/
public class Client {public static void main(String[] args) throws Exception {User user = new User();User clone = (User) user.clone();System.out.println(user == clone); // falseSystem.out.println(user.getAddress() == clone.getAddress()); // false 深克隆}
}

这种方式的逻辑很好理解,就是在重写的clone()方法中,将对象的所有引用类型的属性全部设置为一个新实例化的引用即可。

但是采用这种方式也有一个缺点就是,如果我们User类中引用类型的属性非常多,那么clone()方法需要写很长,而且后面如果有修改,比如在User类中新增了属性,那么这个地方也要修改,并且通过这种方式实现深克隆后,我们也无法再调用上述浅克隆的方式进行浅克隆了。

  1. 序列化实现深克隆:我们可以借助序列化来实现深拷贝。先把对象序列化成流,再从流中反序列化成对象,这样就一定是新的对象了。

序列化的方式有很多,比如我们可以使用各种JSON工具,把对象序列化成SON字符串,然后再从字符串中反序列化成对象。

使用fastjson工具包序列化实现深拷贝:

/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 奖状类*/
public class Citation implements Cloneable, Serializable {private Student student;public void show() {System.out.println(student.getName() + "获得了奖状");}public Student getStudent() {return student;}public void setStudent(Student student) {this.student = student;}@Overrideprotected Citation clone() throws CloneNotSupportedException {return (Citation) super.clone();}
}
/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 学生类*/
public class Student implements Serializable {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}

/*** @author OldGj * @version v1.0* @apiNote 客户端 - 测试深拷贝 - 使用fastjson工具包实现序列化*/
public class CitationTest {public static void main(String[] args) throws Exception {Citation citation = new Citation();citation.setStudent(new Student());String jsonString = JSON.toJSONString(citation);Citation newCitation = JSON.parseObject(jsonString, Citation.class);System.out.println(citation == newCitation); // false System.out.println(citation.getStudent() == newCitation.getStudent()); // false 深拷贝}
}

使用SerializationUtils工具类实现深拷贝

SerializationUtils 是 Apache Commons Lang 库中的一个工具类,用于实现 Java 对象的序列化和反序列化。它提供了一组静态方法,可以方便地将对象序列化为字节数组,或者将字节数组反序列化为对象。
引入Apache Commons Lang库依赖:

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version> <!-- 或者是当前最新版本 -->
</dependency>
/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 客户端 - 测试类 测试深拷贝*/
public class CitationTest2 {public static void main(String[] args) throws CloneNotSupportedException {Citation citation = new Citation();Student student = new Student();student.setName("张三");citation.setStudent(student);Citation cloned = SerializationUtils.clone(citation); //基于序列化实现深拷贝System.out.println(citation==cloned); // falseSystem.out.println(citation.getStudent()==cloned.getStudent()); // false 深克隆Student student1 = new Student();student1.setName("李四");cloned.setStudent(student1); // 修改克隆对象的引用类型属性,原对象的该属性不变System.out.println(citation.getStudent().getName());System.out.println(cloned.getStudent().getName());}
}

注意事项
序列化版本一致性:确保序列化和反序列化的类具有相同的 serialVersionUID,以避免反序列化时出现 InvalidClassException。

Serializable 接口:要序列化一个对象,该对象的类必须实现 Serializable 接口。

SerializationUtils 提供了一种简单而强大的方式来实现对象的序列化和反序列化,以及对象的深度复制,从而简化了 Java 应用程序中的对象操作。Citation类和Student类必须实现Serializable接口,否则会抛NotSerializableException异常。

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

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

相关文章

南邮概率统计与随机过程练习册答案

**南京邮电大学** **概率统计与随机过程练习册答案简介** 本文档是一份精心整理的南京邮电大学概率统计与随机过程课程的练习册答案集。它旨在为学习该课程的学生提供一个详尽的解题参考,帮助他们更好地理解和掌握概率论与统计学的基本概念和方法。 **内容概览:** - **章节…

990-03产品经理与程序员:什么是 IT 与业务协调以及为什么它很重要?

What is IT-business alignment and why is it important? 什么是IT-业务一致性&#xff1f;为什么它很重要&#xff1f; It’s more important than ever that IT and the business operate from the same playbook(剧本). So why do so many organizations struggle to ach…

liunx gcc编译器 以及编译过程

liunx编译器gcc 编译过程 编译过程gccgcc的条件编译gcc 编译指令动态库和静态库 编译过程 预处理 &#xff08;1&#xff09;将所有的#define删除&#xff0c;并且展开所有的宏定义。说白了就是字符替换 &#xff08;2&#xff09;处理所有的条件编译指令&#xff0c;#ifdef …

信息安全计划:它是什么、为什么需要一个以及如何开始

每个组织都需要一个信息安全计划&#xff0c;因为数据已成为世界上最有价值的商品。与所有珍贵的东西一样&#xff0c;数据受到管理机构的严格监管&#xff0c;并且受到每个人&#xff08;包括骗子&#xff09;的觊觎。这就是网络犯罪不断增加的原因——与日益严格的合规环境同…

pdffactory pro 8中文破解版

详细介绍 PdfFactory&#xff0c;PDF文档虚拟打印机&#xff0c;无须Acrobat即可创建Adobe PDF文件&#xff0c;创建PDF文件的方法比其他方法更方便和高效。支持将多个文档整合到一个PDF文件、增加字体和便签、PDF加密、去水印、压缩优化。 FinePrint&#xff0c;Windows虚拟…

DAY29--learning English

一、积累 1.sign up for 2.business trip 3.calendar 4.acne 5.band-aid 6.scar 7.prescription 8.pimple 9.saucy 10.slurp 11.germaphobe 12.shred 13.boggle 14.platser 15.lick 16.sling 17.smack 18.stereotype 19.salmon 20.cable 二、练习 1.牛津原译 calendar. /ˈk…

【编译原理】第五章课后习题(王原生第三版)

前言 课本&#xff1a; 编译原理&#xff08;第三版&#xff09;[王生原、董渊…等编著]习题&#xff1a; 主要习题内容是第一章到第八章&#xff0c;具体内容如下表 章节内容链接第一章课后部分选择题https://blog.csdn.net/Zchengjisihan/article/details/136243955第二章课…

Linux的进程

在Linux中&#xff0c;可以使用多种方式来结束进程。以下是8种常见的方式&#xff1a; 终端中断&#xff08;Ctrl C&#xff09;&#xff1a;在终端中运行的程序可以通过按下Ctrl C组合键来发送SIGINT信号&#xff0c;终止该进程的执行。 kill命令&#xff1a;使用kill命令可…

仿12306校招项目业务一(支付)

业务流程 1. 用户发起支付 当用户抢到票后&#xff0c;开始发起订单支付请求&#xff0c;假设选择支付宝作为支付方式&#xff0c;支付流程如下。 2. 支付结果回调 当用户支付完一笔订单&#xff0c;支付宝付款渠道接收到支付结果后&#xff0c;对请求支付的系统进行支付结果…

线程池(ThreadPoolExecutor,as_completed)和scrapy框架初步构建——学习笔记

用法1&#xff1a;map函数 with ThreadPoolExecutor() as pool: results pool.map(craw,utls)for result in results:print(result) 1.Scrapy框架&#xff1a; 五大结构&#xff1a;引擎&#xff0c;下载器&#xff0c;爬虫&#xff0c;调度器&#xff0c;管道&#x…

Flask数据库操作-Flask-SQLAlchemy

Flask中一般使用flask-sqlalchemy来操作数据库。flask-sqlalchemy的使用介绍如下&#xff1a; 一、SQLAlchemy SQLALchemy 实际上是对数据库的抽象&#xff0c;让开发者不用直接和 SQL 语句打交道&#xff0c;而是通过 Python 对象来操作数据库&#xff0c;在舍弃一些性能开销…

udp服务器【Linux网络编程】

目录 一、UDP服务器 1、创建套接字 2、绑定套接字 3、运行 1&#xff09;读取数据 2&#xff09;发送数据 二、UDP客户端 创建套接字&#xff1a; 客户端不用手动bind 收发数据 处理消息和网络通信解耦 三、应用场景 1、服务端执行命令 2、Windows上的客户端 3…

Visual Studio:Entity设置表之间的关联关系

1、选择表并右键-》新增-》关联 2、设置关联的表及关联关系并“确定”即可

基于Docker和Springboot两种方式安装与部署Camunda流程引擎

文章目录 前言1、Docker安装1.1、拉取Camunda BPM镜像1.2、编写docker启动camunda容器脚本1.3、docker启动脚本1.4、访问验证 2、SpringBoot启动2.1、下载地址2.2、创建SpringBoot项目并配置基础信息2.3、下载SpringBoot项目并在idea中打开2.4、pom修改2.5、application.yml配置…

软件实例,物流货运配货单打印模板软件单据打印查询管理系统软件教程,可以同时打印标签或补打

软件实例&#xff0c;物流货运配货单打印模板软件单据打印查询管理系统软件教程&#xff0c;可以同时打印标签或补打 一、前言 以下软件教程以 佳易王物流单打印查询系统V17.1为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 这个版本在原来基…

PyTorch概述(五)---LINEAR

torch.nn.Linear torch.nn.Linear(in_features,out_features,biasTrue,deviceNone,dtypeNone) 对输入的数据应用一个线性变换&#xff1a; 该模块支持TensorFLoat32类型的数据&#xff1b;在某些ROCm设备上&#xff0c;使用float16类型的数据输入时&#xff0c;该模块在反向传…

C++面试题精选与解析

C面试题精选与解析 一、基础与语法 请问C中的指针和引用有什么区别&#xff1f; 指针是一个变量&#xff0c;存储的是另一个变量的内存地址。指针可以被重新赋值以指向另一个不同的对象。而引用是某个变量的别名&#xff0c;一旦引用被初始化为一个变量&#xff0c;就不能改变…

Java 学习和实践笔记(20):static的含义和使用

static的本义是静止的。在计算机里就表示静态变量。 在Java中&#xff0c;从内存分析图上可以看到&#xff0c;它与类、常量池放在一个区里&#xff1a; 从图可以看到&#xff0c;普通的方法和对象属性&#xff0c;都在heep里&#xff0c;而static则在方法区里。 static声明的…

数据结构-查找与排序

数据结构再往后就是比较零散的各种操作&#xff0c;查找与排序是其中最常出现的&#xff0c;今天来总结一下常用的查找与排序所用的方法 查找 顺序查找 最简单的查找方式&#xff0c;遍历&#xff0c;然后比较 bool search1(int *a,int n,int k){for (int i1;i<n;i){//遍…

Guitar Pro8.2吉他软件2024中文版功能特点介绍

Guitar Pro 8.2是一款功能强大的吉他乐谱软件&#xff0c;专为吉他手、音乐制作人和音乐爱好者设计。它提供了丰富的功能&#xff0c;帮助用户轻松创建、编辑、打印和分享吉他乐谱。以下是Guitar Pro 8.2的主要功能特点&#xff1a; Guitar Pro 2024 win-安装包下载如下&#x…