二、原型模式
文章目录
- 1 基本介绍
- 2 实现方式
- 深浅拷贝
- 目标
- 2.1 使用 Object 的 clone() 方法
- 2.1.1 代码
- 2.1.2 特性
- 2.1.3 实现深拷贝
- 2.2 在 clone() 方法中使用序列化
- 2.2.1 代码
- 2.2.2 特性
- 3 实现的要点
- 4 Spring 中的原型模式
- 5 原型模式的类图及角色
- 5.1 类图
- 5.1.1 不限制语言
- 5.1.2 在 Java 中的类图
- 5.2 角色
- 5.2.1 Prototype ( 原型 )
- 5.2.2 ConcretePrototype ( 具体的原型 )
- 5.2.3 Client ( 使用者 )
- 6 原型模式的优缺点
- 7 原型模式的使用场景
- 8 总结
1 基本介绍
原型模式(Prototype Pattern)是一种创建型设计模式,它允许 通过复制已有的对象来创建新的对象,而无需知道对象创建的细节。
2 实现方式
深浅拷贝
原型模式的实现围绕着 深浅拷贝 的特性展开,其定义如下:
- 浅拷贝(Shallow Copy):只复制对象的 第一层 属性(即 八大基本数据类型 +
String
这个引用数据类型),对于引用类型的属性(除了字符串String
类型外),复制的是内存地址引用,而非对象本身。它存在这种危险:如果原对象的引用类型属性被修改,浅拷贝得到的对象的对应属性也会受到影响。 - 深拷贝(Deep Copy):递归地 复制对象及其所有子对象,创建一个全新的对象,与原对象没有任何关联。
目标
实现一个 Sheep
类,字段为 String name
和 int age
,它能通过 clone()
方法克隆出一模一样的对象。
共有以下 2 种实现:
2.1 使用 Object 的 clone() 方法
2.1.1 代码
public class Sheep implements Cloneable { // 实现了 Cloneable 接口private String name;private int age;private String friend;public Sheep(String name, int age, String friend) {this.name = name;this.age = age;this.friend = friend;}public String getName() {return name;}public int getAge() {return age;}public String getFriend() {return friend;}@Overridepublic Sheep clone() {try {return (Sheep) super.clone(); // 使用 Object 的 clone()} catch (Exception e) { // 如果有异常e.printStackTrace(); // 打印异常return null; // 并返回 null}}public static void main(String[] args) { // 测试程序Sheep sheep = new Sheep("silvery", 6, new Sheep("gold", 13, null));Sheep clone = sheep.clone();System.out.println(sheep == clone);System.out.println("[sheep]: name = " + sheep.getName() + ", age = " + sheep.getAge()+ ", friend = " + sheep.getFriend() + ", friend.name = " + sheep.getFriend().getName());System.out.println("[clone]: name = " + clone.getName() + ", age = " + clone.getAge()+ ", friend = " + clone.getFriend() + ", friend.name = " + clone.getFriend().getName());/* 测试结果如下:false[sheep]: name = silvery, age = 6, friend = cn.me.Sheep@f6f4d33, friend.name = gold[clone]: name = silvery, age = 6, friend = cn.me.Sheep@f6f4d33, friend.name = gold总结:sheep 和 name 不是同一个对象,但属性一样它们的 friend 是同一个 friend,这就是 浅拷贝*/}
}
2.1.2 特性
- 浅拷贝:
Object
自带的clone()
方法是浅拷贝,对于非String
类型的引用类型,它只能拷贝其内存地址。 - 实现简单:虽然这种方式是浅拷贝,但实现起来很简单,如果能确定不使用除
String
类型之外的引用类型,这种方式很方便。
2.1.3 实现深拷贝
如果一个类中除 String
类型之外的引用类型 很少,那么可以像以下这样 单独 对这些引用类型进行 克隆,从而实现深拷贝:
@Override
public Sheep clone() {try {Sheep clone = (Sheep) super.clone();// 对 除 String 之外的引用类型 单独克隆// 如果没有判断空值,则可能会抛出空指针异常 NullPointerExceptionif (clone.friend != null) {clone.friend = this.friend.clone();}return clone;} catch (Exception e) { // 如果有异常e.printStackTrace(); // 打印异常return null; // 并返回 null}
}
2.2 在 clone() 方法中使用序列化
2.2.1 代码
注意:如果要使用序列化,则要实现 Serializable
接口。
public class Sheep implements Cloneable, Serializable { // 实现了 Cloneable 和 Serializable 接口private String name;private int age;private String friend;public Sheep(String name, int age, String friend) {this.name = name;this.age = age;this.friend = friend;}public String getName() {return name;}public int getAge() {return age;}public String getFriend() {return friend;}@Overridepublic Sheep clone() {ByteArrayOutputStream bos = null; // 字节数组输出流ObjectOutputStream oos = null; // 对象输出流ByteArrayInputStream bis = null; // 字节数组输入流ObjectInputStream ois = null; // 对象输入流try {// 序列化:将当前对象以对象流的形式输出bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);oos.writeObject(this);// 反序列化:将当前对象以对象流的形式读取,形成一个新的对象bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);Object clone = ois.readObject();return (Sheep) clone;} catch (Exception e) { // 如果有异常e.printStackTrace(); // 打印异常return null; // 并返回 null} finally {try { // 用完流之后记得关闭if (bos != null) {bos.close();}if (oos != null) {oos.close();}if (bis != null) {bis.close();}if (ois != null) {ois.close();}} catch (Exception e) { // 如果关闭流出现异常e.printStackTrace(); // 则打印异常}}}public static void main(String[] args) { // 测试程序Sheep sheep = new Sheep("silvery", 6, new Sheep("gold", 13, null));Sheep clone = sheep.clone();System.out.println(sheep == clone);System.out.println("[sheep]: name = " + sheep.getName() + ", age = " + sheep.getAge()+ ", friend = " + sheep.getFriend() + ", friend.name = " + sheep.getFriend().getName());System.out.println("[clone]: name = " + clone.getName() + ", age = " + clone.getAge()+ ", friend = " + clone.getFriend() + ", friend.name = " + clone.getFriend().getName());/* 测试结果如下:false[sheep]: name = silvery, age = 6, friend = cn.me.Sheep@421faab1, friend.name = gold[clone]: name = silvery, age = 6, friend = cn.me.Sheep@504bae78, friend.name = gold总结:sheep 和 name 不是同一个对象,但属性一样它们的 friend 不是同一个 friend,但属性一样,这是 深拷贝*/}
}
2.2.2 特性
- 深拷贝:这种方式是深拷贝,它会递归地构建所有对象,从而创建一个与原对象无任何关联的新对象,只是属性相同罢了。
- 实现复杂:这种方式的实现很复杂,涉及到四个流的创建、使用和关闭,要处理的异常也很多。
- 性能开销:这种方式由于需要创建、使用和关闭流,所以可能会消耗一部分性能。
3 实现的要点
- 实现
Cloneable
接口。 - 重写
Object
类的clone()
方法。 - 考虑深浅拷贝的问题。
4 Spring 中的原型模式
对于 ClassPathXmlApplicationContext
类的对象,它的 getBean()
方法继承自 AbstractBeanFactory
抽象类的 getBean()
方法,其内部调用了 doGetBean()
方法,在 doGetBean()
方法中使用了原型模式(这里面具体的逻辑就很复杂了),如下所示:
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args,boolean typeCheckOnly) throws BeansException {// ...else if (mbd.isPrototype()) {prototypeInstance = null;Object prototypeInstance;try {this.beforePrototypeCreation(beanName);prototypeInstance = this.createBean(beanName, mbd, args); // 在这里使用了原型模式} finally {this.afterPrototypeCreation(beanName);}beanInstance = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}// ...
}
5 原型模式的类图及角色
5.1 类图
5.1.1 不限制语言
5.1.2 在 Java 中的类图
5.2 角色
5.2.1 Prototype ( 原型 )
该角色负责 定义 用于复制现有实例来生成新实例的 方法,在 Java 中一般指的是 Object
类,它定义了 native
的 clone()
方法。
5.2.2 ConcretePrototype ( 具体的原型 )
该角色负责 实现 用于复制现有实例来生成新实例的 方法,在 Java 中不仅要继承 Object
类(如果一个类不指定继承的类,则它默认继承 Object
类),还要实现 Cloneable
这个 标记接口,虽然它没有定义方法,但要使用 clone()
方法就得实现它,否则就会抛出 CloneNotSupportedException
(不支持 clone()
方法)的异常。
5.2.3 Client ( 使用者 )
该角色负责 使用 用于复制现有实例来生成新实例的 方法。
6 原型模式的优缺点
优点:
- 性能高:使用原型模式复用的方式创建实例对象,比使用构造器重新创建对象性能要高。
- 流程简单:原型模式可以简化创建的过程,可以直接修改现有的对象实例的值,达到复用的目的。
- 具有动态性:使用构造器创建对象的代码在运行期间时固定的,而使用原型模式可以获取对象运行时的属性,从而 动态地 创建出新的对象。
缺点:
- 实现复杂:必须重写对象的
clone()
方法,且需要考虑 深拷贝 与 浅拷贝 的风险。 - 克隆方法需要通盘考虑:配备克隆方法需要对类的功能进行通盘考虑,特别是对于已有的类,可能需要修改其结构以支持克隆,违背了 开闭原则。
7 原型模式的使用场景
- 对象的创建成本较高:如果创建对象的过程比较复杂或耗时较长,可以使用原型模式通过复制一个现有对象的属性和方法来创建新对象,从而避免昂贵的创建过程。
- 需要创建大量相似的对象:如果需要创建大量相似的对象,可以先创建一个原型对象,然后通过复制原型对象来创建新对象,从而提高对象创建的效率和性能。
- 对象的修改频繁:如果对象的属性需要经常变化,而且每次变化都需要创建一个新的对象,可以使用原型模式,通过复制原型对象来创建新对象并修改其属性,而不需要每次都重新创建新对象。
- 隐藏对象的创建细节:如果创建对象的细节比较复杂,不希望客户端直接与创建对象的过程耦合,可以使用原型模式,客户端只需要通过复制一个已有对象来创建新对象,而无需知道创建的细节。
8 总结
原型模式是一种非常有用的 创建型 设计模式,它 通过复制已有的对象来创建新对象,从而 提高了对象创建的效率和性能。然而,在使用时需要注意 深浅拷贝问题 以及 克隆方法的实现细节,以避免出现不必要的错误。
相关文章:
二、原型模式
文章目录 1 基本介绍2 实现方式深浅拷贝目标2.1 使用 Object 的 clone() 方法2.1.1 代码2.1.2 特性2.1.3 实现深拷贝 2.2 在 clone() 方法中使用序列化2.2.1 代码 2.2.2 特性 3 实现的要点4 Spring 中的原型模式5 原型模式的类图及角色5.1 类图5.1.1 不限制语言5.1.2 在 Java 中…...
【目标检测】Anaconda+PyTorch(GPU)+PyCharm(Yolo5)配置
前言 本文主要介绍在windows系统上的Anaconda、PyTorch、PyCharm、Yolov5关键步骤安装,为使用yolo所需的环境配置完善。同时也算是记录下我的配置流程,为以后用到的时候能笔记查阅。 Anaconda 软件安装 Anaconda官网:https://www.anaconda…...
Django实战项目之进销存数据分析报表——第二天:项目创建和 PyCharm 配置
在上一篇博客中,我们讨论了如何搭建一个全栈 Web 应用的开发环境,包括 Python 环境的创建、Django 和 MySQL 的安装以及前端技术栈的选择。现在,让我们继续深入,学习如何在 PyCharm 中创建一个新的 Django 项目并进行配置。 一…...
静态路由实验
1.实验拓扑图 二、实验要求 1.R6为ISP,接口IP地址均为公有地址,该设备只能配置IP地址,之后不能再对其进行任何配置; 2.R1-R5为局域网,私有IP地址192.168.1.0/24,请合理分配; 3.R1、R2、R4&…...
VSCode STM32嵌入式开发插件记录
要卸载之前搭建的VSCode嵌入式开发环境了,记录一下用的插件。 1.Cortex-Debug https://github.com/Marus/cortex-debug 2.Embedded IDE https://github.com/github0null/eide 3.Keil uVision Assistant https://github.com/jacksonjim/keil-assistant/ 4.RTO…...
linux cpu 占用超100% 分析。
感谢: https://www.cnblogs.com/wolfstark/p/16450131.html 总结: 查看进程中各个线程占用百分比 top -H -p <pid> 某线程100%了 说明 任务处理不过来 会卡 但是永远不可能超100% 系统监视器里面看到的是 所有线程占用的 总和会超100%。 所以最好的情况是&…...
自然学习法和科学学习法
一、自然学习法 自然学习法:什么事自然学习法,特意让kimi来回答了一下。所谓的自然学习法说的俗一点就是野路子学习方法。这种学习方法的特点是“慢”“没有系统性”,学完之后感觉都会了,但是又感觉什么都不会。 二、科学学习法 …...
力扣第二十四题——两两交换链表中的节点
内容介绍 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 示例 1: 输入:head [1,2,3,4] 输出ÿ…...
C语言柔性数组详解
目录 1.柔性数组 2.柔性数组的特点 3.柔性数组的使用 4.柔性数组的优势 1.柔性数组 C99 中,结构体中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。 例如: struct S {char c;int n;int arr[];//柔性数组 }; struct …...
自动驾驶---视觉Transformer的应用
1 背景 在过去的几年,随着自动驾驶技术的不断发展,神经网络逐渐进入人们的视野。Transformer的应用也越来越广泛,逐步走向自动驾驶技术的前沿。笔者也在博客《人工智能---什么是Transformer?》中大概介绍了Transformer的一些内容:…...
预训练语言模型实践笔记
Roberta output_hidden_statesTrue和last_hidden_states和pooler_output 在使用像BERT或RoBERTa这样的transformer模型时,output_hidden_states和last_hidden_state是两个不同的概念。 output_hidden_states: 这是一个布尔值,决定了模型是否应该返回所…...
Perl 哈希
Perl 哈希 Perl 哈希是一种强大的数据结构,用于存储键值对集合。它是 Perl 语言的核心特性之一,广泛应用于各种编程任务中。本文将详细介绍 Perl 哈希的概念、用法和最佳实践。 什么是 Perl 哈希? Perl 哈希是一种关联数组,其中…...
Linux之Mysql索引和优化
一、MySQL 索引 索引作为一种数据结构,其用途是用于提升数据的检索效率。 1、索引分类 - 普通索引(INDEX):索引列值可重复 - 唯一索引(UNIQUE):索引列值必须唯一,可以为NULL - 主键索引(PRIMARY KEY):索引列值必须唯一,不能为NULL,一个表只能有一个主键索引 - 全…...
springboot业务逻辑写在controller层吗
Spring Boot中的业务逻辑不应该直接写在Controller层。 在Spring Boot项目中,通常将业务逻辑分为几个层次,包括Controller层、Service层、Mapper层和Entity层。 1.其中,Controller层主要负责处理HTTP请求,通过注…...
Ubuntu 24.04 LTS 桌面安装MT4或MT5 (MetaTrader)教程
运行脚本即可在 Ubuntu 24.04 LTS Noble Linux 上轻松安装 MetaTrader 5 或 4 应用程序,使用 WineHQ 进行外汇交易。 MetaTrader 4 (MT4) 或 MetaTrader 5 是用于交易外汇对和商品的流行平台。它支持各种外汇经纪商、内置价格分析工具以及通过专家顾问 (EA) 进行自…...
Go基础编程 - 12 -流程控制
流程控制 1. 条件语句1.1. if...else 语句1.2. switch 语句1.3. select 语句1.3.1. select 语句的通信表达式1.3.2. select 的基特性1.3.3. select 的实现原理1.3.4. 经典用法1.3.4.1 超时控制1.3.4.2 多任务并发控制1.3.4.3 监听多通道消息1.3.4.4 default 实现非堵塞读写 2. …...
汽车信息安全--TLS,OpenSSL
目录 TLS相关知识 加密技术 对称加密 非对称加密 数字签名和CA 信任链 根身份证和自签名 双方TLS认证 加密和解密的性能 TLS相关知识 加密技术 TLS依赖两种加密技术 1. 对称加密(symmetric encryption) 2. 非对称加密(asymmetri…...
深入探索 SQL 中的 LIKE 右模糊匹配(LIKE RIGHT)与左模糊匹配(LIKE LEFT)
引言 在数据库操作中,LIKE 子句是执行模糊搜索的强大工具,用于匹配列中的数据与指定的模式。本文将详细介绍 LIKE 子句中的两种常用模式:右模糊匹配(LIKE RIGHT)和左模糊匹配(LIKE LEFT)&#…...
mybatis 多数据源 TDataSource required a single bean, but 2 were found
情况说明: 项目中本来就有一个数据源了,运行的好好的后来又合并了另一个项目,另一个项目也配置了数据源。 于是出现了如下错误: mybatis 多数据源 TDataSource required a single bean, but 2 were found 解决方法:…...
Dubbo SPI 之路由器
1. 背景介绍 Dubbo 是一个高性能的 Java RPC 框架,由阿里巴巴开源并广泛应用于分布式系统中。在 Dubbo 的架构中,SPI(Service Provider Interface)是一个关键组件,允许在运行时动态加载不同的服务实现。SPI 机制提供了…...
Python深度学习环境配置(Pytorch、CUDA、cuDNN),包括Anaconda搭配Pycharm的环境搭建以及基础使用教程(保姆级教程,适合小白、深度学习零基础入门)
全流程导览 一、前言二、基本介绍2.1全过程软件基本介绍2.1.1 Pytorch2.1.2 Anaconda2.1.3 Pycharm2.1.4 显卡GPU及其相关概念2.1.5 CUDA和cuDNN 2.2 各部分相互间的联系和安装逻辑关系 三、Anaconda安装3.1安装Anaconda3.2配置环境变量3.3检验是否安装成功 四、Pycharm安装五、…...
月影护眼大路灯怎么样?书客|月影|霍尼韦尔超硬核实力性能测评pk!
月影护眼大路灯怎么样?选到专业优质的护眼大路灯是真的可以使我们在用眼时减少疲劳感,达到护眼效果,但如果不慎买到劣质的护眼灯产品,不仅达不到健康的环境光,还越用越觉得眼睛疲劳感加重,在水深的护眼灯市…...
邮件安全篇:邮件传输加密(SSL/TLS or STATRTTLS)
1. 前言 使用过邮件客户端的同学一定见过下面这张图。这是客户端账号配置界面,里面有SSL、STARTTLS选项。刚接触邮件客户端的同学肯定会有这些疑问:什么是SSL?什么是STARTTLS?两者有什么区别?具体该如何选择呢&#x…...
【系统架构设计 每日一问】三 Redis支持事务么,Redis的事务如何保证
实际上,关于Redis事务的说法“Redis 的事务只能保证隔离性和一致性(I 和 C),无法保证原子性和持久性(A 和 D)”并不完全准确。下面我将分别解释Redis事务的四个特性:原子性(Atomicit…...
【中项】系统集成项目管理工程师-第4章 信息系统架构-4.3应用架构
前言:系统集成项目管理工程师专业,现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试,全称为“全国计算机与软件专业技术资格(水平)考试”&…...
DasViewer打开Revit输出的fbx格式的模型,为啥一团黑?
答:这个应该是没有读取到贴图文件。贴图文件和obj文件需要在同级目录下面。 DasViewer是由大势智慧自主研发的免费的实景三维模型浏览器,采用多细节层次模型逐步自适应加载技术,让用户在极低的电脑配置下,也能流畅的加载较大规模实景三维模型,提供方便快捷的数据浏览操作。 免…...
【05】LLaMA-Factory微调大模型——初尝微调模型
上文【04】LLaMA-Factory微调大模型——数据准备介绍了如何准备指令监督微调数据,为后续的微调模型提供高质量、格式规范的数据支撑。本文将正式进入模型微调阶段,构建法律垂直应用大模型。 一、硬件依赖 LLaMA-Factory框架对硬件和软件的依赖可见以下…...
Training for Stable Diffusion
1.Training for Stable Diffusion 笔记来源: 1.Denoising Diffusion Probabilistic Models 2.最大似然估计(Maximum likelihood estimation) 3.Understanding Maximum Likelihood Estimation 4.How to Solve ‘CUDA out of memory’ in PyTorch 5.pytorch-stable-d…...
初学51单片机之指针基础与串口通信应用
开始之前推荐一个电路学习软件,这个软件笔者也刚接触。名字是Circuit有在线版本和不在线版本,这是笔者在B站看视频翻到的。 Paul Falstadhttps://www.falstad.com/这是地址。 离线版本在网站内点这个进去 根据你的系统下载你需要的版本红线的是windows…...
【启明智显分享】甲醛检测仪HMI方案:ESP32-S3方案4.3寸触摸串口屏,RS485、WIFI/蓝牙可选
今年,“串串房”一词频繁引发广大网友关注。“串串房”,也被称为“陷阱房”“贩子房”——炒房客以低价收购旧房子或者毛坯房,用极度节省成本的方式对房子进行装修,之后作为精修房高价租售,因甲醛等有害物质含量极高&a…...
在哪里做马可波罗网站/百度网页推广
点击上方 "大数据肌肉猿"关注, 星标一起成长点击下方链接,进入高质量学习交流群今日更新| 950个转型案例分享-大数据交流群本文分为两大节介绍,第一节是数仓建设,第二节是数据治理,内容较长,还请耐心阅读&am…...
佛山网站建设网站制作公司哪家好/关键词有哪些
提回来4个月,关于导航的问题曾经纠结过很久:弄个一体机吧,贵,安装还麻烦,新地图也麻烦(其实主要是贵。。。),家里装宽带电信送华为C8812跟华为C8650,一直都是拿这两个手机当导航用&am…...
某电子商务网站建设的详细策划/电商运营工资一般多少钱一个月
回到目录 众所周知,自从.net中出现了特性(attribute)之后,代码变得更加简洁,可读性更强了,今天主要说一下Conditional特性,Conditional它主要是约束你的代码段在哪种条件下进行执行,我们今天主要针对DEBUG和…...
好的网站推荐一个/上海关键词排名搜索
关注云报洞察深一度一年一度的“618”大促脚步越来越近了。据说,今年的“618”将是史上折扣力度最大的一次。你是不是已经跃跃欲试了?不过,在享受“剁手”快感的同时,你是否会因那些暗流涌动的欺诈风险而畏首畏尾呢?找…...
web服务器做网站/咨询公司
方法介绍 MapReduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。这样做的好处是可以在任务被分解后,可以通过大…...
做免费网站推广开头语/单页应用seo如何解决
以下转载自安富莱电子: http://forum.armfly.com/forum.php NVIC 的全称是 Nested vectored interrupt controller,即嵌套向量中断控制器。对于 M3 和 M4 内核的 MCU,每个中断的优先级都是用寄存器中的 8 位来设置的。 8 位的话就可以设置 2^…...