Java设计模式之创建型-原型模式(UML类图+案例分析)

目录

一、基础概念

二、UML类图

三、角色设计

四、案例分析 

1、通用实现(浅克隆)

2、深克隆

五、总结


一、基础概念

原型模式通过复制已有对象作为原型,通过复制该原型来返回一个新对象,而不是新建对象,说白了就是不断复制相同的对象罢了。

二、UML类图

三、角色设计

角色描述
抽象原型类规定了具体的原型对象必须实现的clone()方法
具体原型类实现抽象原型类的clone()方法,它是可以为复制的对象
访问类使用具体原型类中的clone()方法来复制新的对象

四、案例分析 

1、通用实现(浅克隆)

定义一个学生类,实现Cloneable接口并重写clone方法。

super.clone()是基于对象在内存中的二进制位面值进行复制的一种浅拷贝实现。它的优点是效率高,不需要进行逐字段复制,因此不会调用对象的构造函数,也就是不需要经历初始化的过程。

    @Overrideprotected Student clone(){Student student = null;try {student = (Student) super.clone();}catch (Exception e){e.printStackTrace();}return student;}

其内部属性有name和Teacher类,实现有参构造,get和set方法,重写toString()方法。 

public class Student implements Cloneable{private String name;@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", teacher=" + teacher +'}';}private Teacher teacher;public Student(String name, Teacher teacher) {this.name = name;this.teacher = teacher;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Teacher getTeacher() {return teacher;}public void setTeacher(Teacher teacher) {this.teacher = teacher;}@Overrideprotected Student clone(){Student student = null;try {student = (Student) super.clone();}catch (Exception e){e.printStackTrace();}return student;}
}

写一个主方法测试:

    public static void main(String[] args) {Teacher teacher = new Teacher("赵老师");Student student = new Student("李四",teacher);Student clone = student.clone();clone.getTeacher().setName("老王老师");System.out.println(student);System.out.println(clone);}

运行结果如下:

运行完毕以后会发现一个问题,就是我克隆出来的学生换了新的老王老师以后,怎么原来学生对象的老师也变成了老王老师,这明显不对呀!

从运行的结果上分析,应该是teacher共用同一个内存地址,意味着复制的不是值,而是引用的地址,这正是浅拷贝的特征:

1、对基本数据类型进行值复制

2、对引用类型仅复制引用,没有复制引用的对象

解决办法是在clone时,需要深拷贝teacher对象,断开student和clone的teacher对象引用关系,使两者独立。

2、深克隆

Student类需要实现Serializable接口,并自定义了deepClone方法实现深克隆,每一行代码解释如下:

1、创建字节数组输出流,用于存放序列化后的二进制数据。

ByteArrayOutputStream bos = new ByteArrayOutputStream();

2、 基于字节数组输出流创建对象输出流,用于序列化对象。

ObjectOutputStream oos = new ObjectOutputStream(bos);

3、 将当前对象写入对象输出流进行序列化,序列化后的二进制数据存入字节数组输出流。

oos.writeObject(this);

4、获取字节数组输出流中的数据(序列化后的二进制数据),封装为字节数组输入流。

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

5、基于字节数组输入流创建对象输入流,用于反序列化对象。

ObjectInputStream ois = new ObjectInputStream(bis);

6、从对象输入流中读取流数据并反序列化生成对象,返回反序列化得到的学生对象副本。

return (Student) ois.readObject();

完整的关键代码如下: 

public class Student implements Cloneable, Serializable {//构造、get和set方法、toString()方法省略public Student deepClone(){try{ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(this);ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);return (Student) ois.readObject();}catch (Exception e){e.printStackTrace();return null;}}}

总结起来,这段代码使用了序列化和反序列化来实现对象的深克隆,核心思路是将对象写入流,然后从流里再读出来克隆对象。 

同时Teacher类也需要实现Serializable序列化接口,关键代码如下:

public class Teacher implements Serializable {}

但不需要实现深克隆,原因如下:

在通过序列化实现Student深克隆时,会自动将Student对象所引用的Teacher对象全部序列化,并在反序列化时重新创建出一个新的Teacher对象。

Teacher对象已经在这个序列化/反序列化的过程中被自动深克隆了,不需要再单独实现深克隆方法。

主方法测试:

    public static void main(String[] args) {Teacher teacher = new Teacher("赵老师");Student student = new Student("李四",teacher);Student clone = student.deepClone();clone.getTeacher().setName("老王老师");System.out.println(student);System.out.println(clone);}

运行结果如下: 

五、总结

优点:

1、避免重复创建成本高的对象。

2、客户端可以直接获得对象副本,不需要知道如何创建。

3、可以动态添加或者修改复制逻辑。

缺点:

1、需要为每一个类配置一个克隆方法。

2、复制对象的成本也存在,特别是深拷贝。

3、需要注意隔离对象状态,避免相互影响。

应用场景:

1、对象的创建成本比较大,可以通过复制原型对象避免重复创建。

2、需要重复创建相似对象时可以考虑原型模式。

3、需要避免使用子类式继承改变对象结构时。

符合的设计原则:

1、开闭原则(Open Closed Principle)

原型模式通过克隆生成新对象,而不需要修改源对象的类,对扩展开放,对修改关闭。

2、组合复用原则(Composite Reuse Principle)

原型模式复用的是对象,不需要通过继承创建子类,可以更灵活地复用对象。

3、单一职责原则(Single Responsibility Principle)

原型类只需要实现Cloneable接口,不需要其他责任,专注于复制自己。

4、里氏替换原则(Liskov Substitution Principle)

原型模式生成的对象和原对象是一致的,扩展也不会破坏原有系统。

5、依赖倒转原则(Dependency Inversion Principle)

客户端只依赖于原型类的接口,不依赖具体实现,降低了依赖。

原型模式通过对象复制获取实例,避免重复创建开销大的对象,是一种快速获取对象副本的模式,但需要注意副本状态的一致性管理。

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

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

相关文章

重磅IntelliJ IDEA 2023.2 新版本即将发布,拥抱 AI

IntelliJ IDEA 近期连续发布多个EAP版本,官方在对用户体验不断优化的同时,也新增了一些不错的功能,尤其是人工智能助手补充,AI Assistant,相信在后续IDEA使用中,会对开发者工作效率带来不错的提升。 以下是…

一个Transformer在尺度上适合多模态扩散的所有分布

文章目录 One Transformer Fits All Distributions in Multi-Modal Diffusion at Scale摘要本文方法实验结果 One Transformer Fits All Distributions in Multi-Modal Diffusion at Scale 摘要 本文提出了一个统一的扩散框架(UniDiffuser)来拟合一个模型中与一组多模态数据相…

【来不及刷题之】43、最小栈(PriorityQueue)

因为要在常量时间内查询出最小值&#xff0c;所以需要有另外的数据结构维护最小值&#xff0c;很自然地想到了“堆”这个结构&#xff0c;“最小堆”的堆顶元素刚好是最小值因此出栈和入栈的同时也要维护好最小堆 class MinStack {PriorityQueue<Integer> heap;LinkedLi…

Kubernetes service服务的发布 - kube-proxy(负载均衡器)-IPVS

目录 Service Service将内部的pod暴露到外面&#xff0c;让用户可以访问 负载均衡策略&#xff1a; Service 的类型&#xff1a; 案例&#xff1a;Service服务发布案例 扩展&#xff1a;我们在案例再加入一个探针的使用 更改后的my_nginx.yaml文件&#xff1a; 创建Pod&…

Langchain 新手完全指南

Langchain 可能是目前在 AI 领域中最热门的事物之一&#xff0c;仅次于向量数据库。 它是一个框架&#xff0c;用于在大型语言模型上开发应用程序&#xff0c;例如 GPT、LLama、Hugging Face 模型等。 它最初是一个 Python 包&#xff0c;但现在也有一个 TypeScript 版本&…

Linux常用命令——env命令

在线Linux命令查询工具 env 显示系统中已存在的环境变量 补充说明 env命令用于显示系统中已存在的环境变量&#xff0c;以及在定义的环境中执行指令。该命令只使用"-“作为参数选项时&#xff0c;隐藏了选项”-i"的功能。若没有设置任何选项和参数时&#xff0c;…

webpack笔记一

文章目录 什么是webpack安装webpack一、创建配置项二、安装webpack局部安装(推荐)全局安装 三、安装webpack-cli(可选) 核心概念入口(entry)出口(output)loader插件(plugin)模式(mode) 项目实例webpack基本使用 html打包插件&#xff1a;html-webpack-plugin文件拷贝插件&#…

[sqoop]导入数据

一、覆盖导入 例如维度表&#xff0c;每次导入的数据需要覆盖上次导入的数据。 hive-overwrite参数&#xff1a;实现覆盖导入 hive-import参数&#xff1a;表示向hive表导入 hive-table参数&#xff1a;指定目标hive库表 sqoop import \ --connect jdbc:mysql://hadoop1:3…

基于单片机的老人防摔倒的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;通过LCD1602液晶显示屏显示当前的经纬度及时间的信息&#xff1b;温度传感器采集当前体温&#xff1b;通过GPS接收模块获得当前位置的位置的经度、纬度、时间和高度等信息&#xff1b;通过ADXL345检测老人摔倒的一瞬间重力加速度通…

【opencv之cv::Mat数据深拷贝和浅拷贝探讨】

cv::Mat数据深拷贝和浅拷贝 cv::Mat 拷贝方法实验测试1.matA matSrc2.matB(matSrc)3.matC matSrc.clone()4.matSrc.copyTo(matD) 很多时候写程序除了一个强大的架构&#xff0c;细节也很重要&#xff0c;俗话说的话细节决定成败嘛&#xff0c;在使用cv::Mat做图片处理的时候发…

VSCODE 设置同步network Error 问题

前言 这个问题等解决方法如下&#xff1a; 获取到github以及vscode-auth.github.com的ip&#xff0c;添加到host&#xff0c;随后使用命令行刷新host&#xff0c;重新认证即可 第一步&#xff0c;查看log文件&#xff0c; 打开 vscode&#xff0c;使用快捷指令ctrl(command)…

虹科分享 | 如何基于IO-Link wireless方案实现工厂数据采集和状态监测

数据和数字化是工业4.0变革的关键驱动因素。从整个工厂的传感器获取数据&#xff0c;除了优化制造计划和流程外&#xff0c;还能实现强大的分析和决策。目前&#xff0c;基于数据的应用正在催生更多智能解决方案&#xff0c;以提高制造业的灵活性和敏捷性&#xff0c;进而提高效…