Java 设计模式——原型模式

目录

  • 1.概述
  • 2.结构
  • 3.实现
    • 3.1.浅拷贝
    • 3.2.深拷贝
      • 3.2.1.通过对象序列化实现深拷贝(推荐)
      • 3.2.2.重写 clone() 方法来实现深拷贝
  • 4.优缺点
  • 5.使用场景

1.概述

(1)原型模式 (Prototype Pattern) 是一种创建型设计模式,是通过复制(克隆)现有对象来创建新对象的模式。它允许我们创建一个原型对象,然后通过复制该原型对象来创建新的对象,而无需通过实例化类来创建新的对象

(2)在原型模式中,一个类将自身的实例作为原型,通过复制这个原型来创建新的对象。这个过程隐藏了对象的创建细节,而且可以提高创建对象的效率。

(3)原型模式基于对象的复制,可以分为浅拷贝和深拷贝两种形式:

  • 浅拷贝:复制对象时,仅仅复制对象的引用,而不复制对象本身。新对象和原对象共享同一个引用,修改一个对象会影响到另一个对象。
  • 深拷贝:复制对象时,不仅复制对象的引用,还复制对象本身,创建一个独立的对象。新对象和原对象互不影响,修改一个对象不会影响到另一个对象。

(4)在实现原型模式时,通常需要实现一个 Cloneable 接口(或类似的机制),该接口标识类具有复制自己的能力。具体的实现细节则根据语言和框架的不同而有所差异。

2.结构

(1)原型模式包含如下角色:

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

(2)接口类图如下:
在这里插入图片描述

3.实现

Java 中的 Object 类中提供了 clone() 方法来实现浅克隆Cloneable 接口是上面的类图中的抽象原型类,而实现了 Cloneable 接口的子实现类就是具体的原型类。

3.1.浅拷贝

Address.java

public class Address {int id;String addressName;public Address(int id, String addressName) {this.id = id;this.addressName = addressName;}
}

Person.java

public class Person implements Cloneable{private int id;private String name;private Address address;public String getName() {return name;}public Person(int id, String name, Address address) {this.id = id;this.name = name;this.address = address;System.out.println("具体的原型对象创建完成!");}@Overrideprotected Object clone() throws CloneNotSupportedException {System.out.println("具体原型复制成功!");return (Person) super.clone();}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +", address=" + address +'}';}}

Client.java

public class Client {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person(1, "小华", new Address(1, "北京"));Person person2 = (Person) person1.clone();System.out.println("person1: " + person1);System.out.println("person2: " + person2);System.out.println("person1.getName() == person2.getName() 的结果为: " + (person1.getName() == person2.getName()));System.out.println("person1 == person2 的结果为: " + (person1 == person2));}
}

输出结果如下图所示:

在这里插入图片描述

3.2.深拷贝

3.2.1.通过对象序列化实现深拷贝(推荐)

先将 Address 类和 Person 类实现 Serializable 接口,然后再修改 Client.java 中的代码即可。

Client.java

public class Client {public static void main(String[] args) throws Exception {Person person1 = new Person(1,"小华",new Address(1,"北京"));//创建对象输出流对象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\testData\\a.txt"));//写对象oos.writeObject(person1);//释放资源oos.close();//创建对象输入流对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\testData\\a.txt"));//读取对象Person person2 = (Person) ois.readObject();//释放资源ois.close();System.out.println("person1:"+person1);System.out.println("person2:"+person2);System.out.println("person1.getName() == person2.getName()的结果为:"+(person1.getName() == person2.getName()));System.out.println("person1 == person2的结果为:"+(person1 == person2));}
}

在这里插入图片描述

3.2.2.重写 clone() 方法来实现深拷贝

public class Person implements Cloneable {private int id;private String name;private Address address;public String getName() {return name;}public Person(int id, String name, Address address) {this.id = id;this.name = name;this.address = address;System.out.println("具体的原型对象创建完成!");}@Overridepublic Object clone() throws CloneNotSupportedException {System.out.println("具体原型复制成功!");Person person = null;person = (Person)super.clone();//对引用数据类型单独处理person.name = new String(name);person.address = (Address)address.clone();return person;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +", address=" + address +'}';}
}

4.优缺点

(1)原型模式具有以下优点:

  • 减少对象的创建成本:原型模式通过复制现有对象来创建新对象,避免了使用构造函数的开销,提高了对象的创建效率。
  • 简化对象的创建过程:使用原型模式,不需要关心对象的具体实现细节,只需复制一个现有对象即可得到新的对象,简化了对象的创建过程。
  • 支持动态添加和修改对象的属性:可以通过修改现有对象的属性来创建新对象,避免了在代码中显式设置对象属性的麻烦。
  • 提供了一种可扩展的创建方式:原型模式通过复制现有对象,可以创建出多个具有相同属性的对象,也可以根据需要修改部分属性,从而具有更高的灵活性和可扩展性。

(2)原型模式也存在一些缺点:

  • 需要实现 Cloneable 接口或类似的机制:在一些语言和框架中,实现原型模式需要实现 Cloneable 接口或类似的机制,这对于某些编程语言来说可能需要额外的工作。
  • 深拷贝可能较为复杂:如果需要复制的对象存在引用类型的成员变量,深拷贝可能需要额外的处理来确保所有引用对象也能被正确地复制。
  • 对象复杂性限制:对于包含循环引用或复杂对象图的对象,可能会导致复制过程变得复杂或不可行。

(3)综上所述,原型模式在某些情况下可以提供高效、灵活和可扩展的对象创建方式,但使用时需注意克隆的实现细节和对象的复杂性。

5.使用场景

(1)原型模式适用于以下场景:

  • 对象创建成本高:当对象的创建成本较高时,例如需要进行复杂的计算、数据读取或网络请求等操作,可以使用原型模式复制现有对象来提高创建效率。
  • 对象初始化复杂:当对象的初始化过程较为复杂,包含多个步骤或依赖关系较多时,可以使用原型模式来复制一个已经初始化好的对象,避免重新执行初始化过程。
  • 动态创建和定制对象:当需要根据一些条件动态创建和定制对象时,原型模式可以提供一种更加灵活的创建方式。通过复制现有对象并根据需要修改部分属性,即可创建出符合条件的新对象。
  • 避免构造函数调用:在某些场景下,使用构造函数创建对象可能不可行或不符合需要。例如,某些框架中对象的创建由框架负责,通过原型模式可以避免直接调用构造函数。
  • 对象的状态变化较小:当对象的状态变化较小,只是部分属性需要修改时,使用原型模式可以避免重新创建对象,提高了性能。

(2)总的来说,原型模式适用于需要复制和创建新对象的场景,尤其是在对象的创建成本较高或初始化复杂的情况下,使用原型模式可以提高创建效率和灵活性。

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

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

相关文章

DNS协议详解

DNS协议详解 DNS协议介绍DNS解析过程DNS查询的方式递归查询迭代查询区别 DNS协议介绍 DNS 协议是一个应用层协议,它建立在 UDP 或 TCP 协议之上,默认使用 53 号端口。该协议的功能就是将人类可读的域名 (如,www.qq.com) 转换为机器可读的 IP…

uniapp 微信小程序 页面+组件的生命周期顺序

uniapp 微信小程序 页面组件的生命周期顺序 首页页面父组件子组件完整顺序参考资料 首页 首页只提供了一个跳转按钮。 <template><view><navigator url"/pages/myPage/myPage?namejerry" hover-class"navigator-hover"><button ty…

智慧工厂4G+蓝牙+UWB+RTK人员定位系统解决方案

人员定位在智慧工厂的应用正逐渐受到重视&#xff0c;通过使用现代化的技术和智能终端设备&#xff0c;工厂管理者能够实时定位和跟踪员工的位置&#xff0c;方便进行人员调度管理和监督人员的工作情况&#xff1b;人员遇到紧急情况&#xff0c;可通过定位设备一键报警求救&…

vue 快速自定义分页el-pagination

vue 快速自定义分页el-pagination template <div style"text-align: center"><el-paginationbackground:current-page"pageObj.currentPage":page-size"pageObj.page":page-sizes"pageObj.pageSize"layout"total,prev,…

安全文件传输:如何降低数据丢失的风险

在当今数字化时代&#xff0c;文件传输是必不可少的一项工作。但是&#xff0c;数据丢失一直是一个令人头疼的问题。本文将探讨一些减少数据丢失风险的方法&#xff0c;包括加密、备份和使用可信的传输协议等。采取这些措施将有助于保护数据免受意外丢失的危险。 一、加密保护数…

24考研数据结构-栈

目录 第三章 栈和队列3.1栈&#xff08;stack&#xff09;3.1.1栈的基本概念栈的基本概念知识回顾 3.1.2 栈的顺序存储上溢与下溢栈的顺序存储知识回顾 3.1.3栈的链式存储链栈的基本操作 第三章 栈和队列 3.1栈&#xff08;stack&#xff09; 3.1.1栈的基本概念 栈的定义 栈…

通过ETL自动化同步飞书数据到本地数仓

一、飞书数据同步到数据库需求 使用飞书的企业都有将飞书的数据自动同步到本地数据库、数仓以及其他业务系统表的需求&#xff0c;主要是为了实现飞书的数据与业务系统进行流程拉通或数据分析时使用&#xff0c;以下是一些具体的同步场景示例&#xff1a; 组织架构同步&#…

9.NIO非阻塞式网络通信入门

highlight: arduino-light Selector 示意图和特点说明 一个 I/O 线程可以并发处理 N 个客户端连接和读写操作&#xff0c;这从根本上解决了传统同步阻塞 I/O 一连接一线程模型。架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。 服务端流程 1、当客户端连接服务端时&…

ADS仿真低噪声放大器学习笔记

ADS仿真低噪声放大器 文章目录 ADS仿真低噪声放大器1. 安装晶体管的库文件2. 直流分析DC Tracing3. 偏置电路的设计4. 稳定性分析5. 输入匹配和输出匹配 设计要求&#xff1a; 工作频率&#xff1a;2.4~2.5GHz ISM频段 噪声系数&#xff1a;NF < 0.7 增益&#xff1a;Gain &…

分享200+个关于AI的网站

分享200个关于AI的网站 欢迎大家访问&#xff1a;https://tools.haiyong.site/ai 快速导航 AI 应用AI 写作AI 编程AI 设计AI 作图AI 训练模型AI 影音编辑AI 效率助手 AI 应用 文心一言: https://yiyan.baidu.com/ 百度出品的人工智能语言模型 ChatGPT: https://chat.openai.c…

人脸检测实战-insightface

目录 简介 一、InsightFace介绍 二、安装 三、快速体验 四、代码实战 1、人脸检测 2、人脸识别 五、代码及示例图片链接 简介 目前github有非常多的人脸识别开源项目&#xff0c;下面列出几个常用的开源项目&#xff1a; 1、deepface 2、CompreFace 3、face_recogn…

【Python 实战】---- 批量识别图片中的文字,存入excel中【使用百度的通用文字识别】

分析 1. 获取信息图片示例 2. 运行实例 3. 运行结果 4. 各个文件的位置 实现 1. 需求分析 识别图片中的文字【采用百度的通用文字识别】;文字筛选,按照分类获取对应的文本;采用 openpyxl 实现将数据存入 excel 中。2. 获取 access_token 获取本地缓存的

网络安全大厂面试题

自我介绍 有没有挖过src&#xff1f; 平时web渗透怎么学的&#xff0c;有实战吗&#xff1f;有过成功发现漏洞的经历吗&#xff1f; 做web渗透时接触过哪些工具 xxe漏洞是什么&#xff1f;ssrf是什么&#xff1f; 打ctf的时候负责什么方向的题 为什么要搞信息安全&#xff0c;对…

数据结构之顺序表

一、概念及结构 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下采用数组存 储。在数组上完成数据的增删查改。 顺序表一般可以分为&#xff1a; 1. 静态顺序表&#xff1a;使用定长数组存储元素。 2. 动态顺序表&#xff1a;使用动…

django学习笔记(1)

django创建项目 先创建一个文件夹用来放django的项目&#xff0c;我这里是My_Django_it 之后打开到该文件下&#xff0c;并用下面的指令来创建myDjango1项目 D:\>cd My_Django_itD:\My_Django_it>"D:\zzu_it\Django_learn\Scripts\django-admin.exe" startpr…

Websocket协议-http协议-tcp协议区别和相同点

通讯形式 单工通讯-数据只能单向传送一方来发送数据&#xff0c;另一方来接收数据 半双工通讯-数据能双向传送但不能同时双向传送 全双工通讯-数据能够同时双向传送和接受 注&#xff1a;http的通讯方式是分版本 http1.0&#xff1a;单工。因为是短连接&#xff0c;客户端…

malloc(1) 会分配多大的虚拟内存?

malloc() 分配的是虚拟内存。 如果分配后的虚拟内存没有被访问的话&#xff0c;虚拟内存是不会映射到物理内存的&#xff0c;这样就不会占用物理内存了。 只有在访问已分配的虚拟地址空间的时候&#xff0c;操作系统通过查找页表&#xff0c;发现虚拟内存对应的页没有在物理内…

TEE GP(Global Platform)技术委员会及中国任务小组

TEE之GP(Global Platform)认证汇总 一、TEE GP技术委员会 二、GP中国任务小组 参考&#xff1a; GlobalPlatform Certification - GlobalPlatform

MultipartFile类型接收上传文件报出的UncheckedIOException以及删除tomcat临时文件失败源码探索

1、描述异常背景&#xff1a; 因为需要分析数据&#xff0c;待处理excel文件的数据行数太大&#xff0c;手动太累&#xff0c;花半小时写了一个定制的数据入库工具&#xff0c;改成了通用的&#xff0c;整个项目中的万级别数据都在工具上分析&#xff0c;写SQL进行分析&#x…

对原型、原型链的理解

在 JavaScript 中是使用构造两数来新建一个对象的&#xff0c;每一个构造函数的内部都有一个 prototype 属性&#xff0c;它的属性值是一个对象&#xff0c;这个对象包含了可以由该构造西数的所有实例共享的属性和方法。当使用构造函数新建一个对象后&#xff0c;在这个对象的内…