设计模式之禅之设计模式-原型模式
设计模式之禅之设计模式-原型模式
一:原型模式的定义
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式(Prototype Pattern)的简单程度仅次于单例模式和迭代器模式。正是由于简单,使用的场景才非常地多。
原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这个对象是可拷贝的,为什么说是“标示”呢?翻开JDK的帮助看看Cloneable是一个方法都没有的,这个接口只是一个标记作用,在JVM中具有这个标记的对象才有可能被拷贝。那怎么才能从“有可能被拷贝”转换为“可以被拷贝”呢?方法是覆盖clone()方法,是的,你没有看错是重写clone()方法,看看我们上面Mail类中的clone方法.该方法重写了Object对象的方法
二:原型模式的优点
● 性能优良
原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
● 逃避构造函数的约束
这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的(参见13.4节)。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。
三:原型模式的应用场景
● 资源优化场景
类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
● 性能和安全要求的场景
通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
● 一个对象多个修改者的场景
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与Java融为一体,大家可以随手拿来使用。
四:原型模式的注意事项
构造函数不会被执行
注意浅拷贝。你可能会比较奇怪,为什么在Mail那个类中就可以使用String类型,而不会产生由浅拷贝带来的问题呢?内部的数组和引用对象才不拷贝,其他的原始类型比如int、long、char等都会被拷贝,但是对于String类型,Java就希望你把它认为是基本类型,它是没有clone方法的,处理机制也比较特殊,通过字符串池(stringpool)在需要的时候才在内存中创建新的字符串,读者在使用的时候就把String当做基本类使用即可。
使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象。
深拷贝还有一种实现方式就是通过自己写二进制流来操作对象,然后实现对象的深拷贝,这个大家有时间自己实现一下
深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。
五:clone和fianl两个冤家
你要实现深拷贝的梦想在final关键字的威胁下破灭了,路总是有的,我们来想想怎么修改这个方法:删除掉final关键字,这是最便捷、安全、快速的方式
你要使用clone方法,在类的成员变量上就不要增加final关键字。
六:原型模式最佳实践
可以这样理解:一个对象的产生可以不由零起步,直接从一个已经具备一定雏形的对象克隆,然后再修改为生产需要的对象。也就是说,产生一个人,可以不从1岁长到2岁,再到3岁…也可以直接找一个人,从其身上获得DNA,然后克隆一个,直接修改一下就是30岁了!我们讲的原型模式也就是这样的功能
七:原型模式例子
【1】原型模式的模板
package com.javagpt.design;import java.util.ArrayList;
import java.util.List;/*** 深层次拷贝* (1)深拷贝还有一种实现方式就是通过自己写二进制流来操作对象,然后实现对象的深拷贝,这个大家有时间自己实现一下* (2)深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。** @author javagpt*/
public class Thing2 implements Cloneable {private ArrayList<String> list = new ArrayList<String>();@Overrideprotected Thing2 clone() throws CloneNotSupportedException {Thing2 thing2 = null;thing2 = (Thing2) super.clone();thing2.list = (ArrayList<String>) this.list.clone();return thing2;}public List<String> getList() {return list;}public void setList(String a) {this.list.add(a);}}
【2】浅拷贝
package com.javagpt.design;import java.util.ArrayList;
import java.util.List;/*** 浅拷贝** @author javagpt* (1)JVM做了一个偷懒的拷贝动作,Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象* 的内部元素地址,这种拷贝就叫做浅拷贝* (2)非常不安全*/
public class Thing implements Cloneable {private List<String> list = new ArrayList<String>();@Overrideprotected Thing clone() throws CloneNotSupportedException {Thing thing = null;thing = (Thing) super.clone();return thing;}public List<String> getList() {return list;}public void setList(String a) {this.list.add(a);}}
【3】深拷贝
package com.javagpt.design;import java.util.ArrayList;
import java.util.List;/*** 深层次拷贝* (1)深拷贝还有一种实现方式就是通过自己写二进制流来操作对象,然后实现对象的深拷贝,这个大家有时间自己实现一下* (2)深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。** @author javagpt*/
public class Thing2 implements Cloneable {private ArrayList<String> list = new ArrayList<String>();@Overrideprotected Thing2 clone() throws CloneNotSupportedException {Thing2 thing2 = null;thing2 = (Thing2) super.clone();thing2.list = (ArrayList<String>) this.list.clone();return thing2;}public List<String> getList() {return list;}public void setList(String a) {this.list.add(a);}}
【4】客户端测试
package com.javagpt.design;import java.util.List;public class ClientTest {public static void main(String[] args) throws CloneNotSupportedException {//test01();//test02();test03();}/*** 原型模式:模板测试** @throws CloneNotSupportedException*/public static void test01() throws CloneNotSupportedException {Mail mail = new Mail("javagpt", "go smx", "emailtojavagpt", "javagpt@163.com");//ClientTest.main()com.javagpt.design.Mail@2a5330System.out.println("ClientTest.main()" + mail.toString());Mail mail2 = mail.clone();System.out.println("ClientTest.main()" + mail2.toString());//ClientTest.main()com.javagpt.design.Mail@18872380}/*** 原型模式:浅拷贝** @throws CloneNotSupportedException*/public static void test02() throws CloneNotSupportedException {Thing thing1 = new Thing();thing1.setList("小李");Thing thing2 = thing1.clone();thing1.setList("小张");List<String> t = thing1.getList();List<String> t2 = thing2.getList();for (int i = 0; i < t.size(); i++) {System.out.println("ClientTest.test02(t==>)" + t.get(i));}for (int i = 0; i < t2.size(); i++) {System.out.println("ClientTest.test02(t2==>)" + t2.get(i));}//ClientTest.test02(t==>)小李//ClientTest.test02(t==>)小张//ClientTest.test02(t2==>)小李//ClientTest.test02(t2==>)小张}/*** 原型模式:深拷贝** @throws CloneNotSupportedException*/public static void test03() throws CloneNotSupportedException {Thing2 thing2a = new Thing2();thing2a.setList("小李");Thing2 thing2b = thing2a.clone();thing2a.setList("小张");List<String> t = thing2a.getList();List<String> t2 = thing2b.getList();for (int i = 0; i < t.size(); i++) {System.out.println("ClientTest.test02(t==>)" + t.get(i));}for (int i = 0; i < t2.size(); i++) {System.out.println("ClientTest.test02(t2==>)" + t2.get(i));}//ClientTest.test02(t==>)小李//ClientTest.test02(t==>)小张//ClientTest.test02(t2==>)小李}
}
相关文章:
设计模式之禅之设计模式-原型模式
设计模式之禅之设计模式-原型模式 一:原型模式的定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 原型模式(Prototype Pattern)的简单程度仅次于单例模式和迭代器模式。正是由于简单,使用的场景才非常地多。 原型模式的核心是一…...
Spring的循环依赖问题
文章目录 1.什么是循环依赖2.代码演示3.分析问题4.问题解决5.Spring循环依赖6. 疑问点6.1 为什么需要三级缓存6.2 没有三级缓存能解决吗?6.3 三级缓存分别什么作用 1.什么是循环依赖 上图是循环依赖的三种情况,虽然方式有点不一样,但是循环依…...
RT-DETR算法改进:更换损失函数DIoU损失函数,提升RT-DETR检测精度
💡本篇内容:RT-DETR算法改进:更换损失函数DIoU损失函数 💡本博客 改进源代码改进 适用于 RT-DETR目标检测算法(ultralytics项目版本) 按步骤操作运行改进后的代码即可🚀🚀🚀 💡改进 RT-DETR 目标检测算法专属 文章目录 一、DIoU理论部分 + 最新 RT-DETR算法…...
【ICE】2:基于webrtc的 ice session设计及实现
工厂函数:CreateICESession_t 外部声明,sdk内部实现。创建IICESession :外部可见,内部也可见 /// Factory function prototype. How you get this factory will depend on how you are linking with /// this code. typedef IICESession *( *CreateICESession_t )( const…...
Vue组件传
跟禹神学vue--总结 1 父组件给子组件传递参数--props传参 (1)父组件中准备好数据 data() {return {todos:[{id:001,title:01,done:true},{id:002,title:02,done:false},{id:003,title:03,done:true}]} } (2)父组件中引入子组件…...
轻量封装WebGPU渲染系统示例<25>- 颜色附件数据更新替换(源码)
当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/ColorAttachmentReplace.ts 此示例基于此渲染系统实现,当前示例TypeScript源码如下: const rttTex0 { diffuse: { uuid: rtt0, rttTexture: {} } }; c…...
c语言练习第11周(1~5)
数列 1 1 2 3 5 8 13 21 ... 被称为斐波纳数列。 输入若干个正整数N,输出这个序列的前 N 项的和。 题干数列 1 1 2 3 5 8 13 21 ... 被称为斐波纳数列。 输入若干个正整数N,输出这个序列的前 N 项的和。输入样例3 5 4 1输出样例…...
阿里云国际站服务器如何升级内存容量?
阿里云服务器是阿里云供给的计算服务,它具有高效安稳、可扩展性强等特色,适用于各种应用环境。在运用阿里云服务器的过程中,或许会遇到内存容量缺乏的状况,这时候就需求晋级内存容量。那么,阿里云服务器怎么晋级内存容…...
神经网络(第二周)
一、简介 1.1 需求预测示例 1.1.1 逻辑回归算法 根据价格预测商品是否畅销。特征:T恤的价格;分类:销售量高1/销售量低0;使用逻辑回归算法进行分类,拟合效果如下图所示: 1.1.2 神经元和神经网络 将逻辑回…...
《网络协议》04. 应用层(DNS DHCP HTTP)
title: 《网络协议》04. 应用层(DNS & DHCP & HTTP) date: 2022-09-05 14:28:22 updated: 2023-11-12 06:55:52 categories: 学习记录:网络协议 excerpt: 应用层、DNS、DHCP、HTTP(URI & URL,ABNF…...
springboot自己添加的配置文件没有绿色叶子问题
在IntelliJ IDEA中,不同文件类型通常会有不同的图标,以便更容易识别它们。如果您的自己添加的 .properties 文件和项目中自动生成的 .properties 文件显示不同的图标,这可能是因为它们被识别为不同的文件类型。 通常情况下,Intel…...
【Java】定时任务 - Timer/TimerTask 源码原理解析
一、背景及使用 日常实现各种服务端系统时,我们一定会有一些定时任务的需求。比如会议提前半小时自动提醒,异步任务定时/周期执行等。那么如何去实现这样的一个定时任务系统呢? Java JDK提供的Timer类就是一个很好的工具,通过简单…...
SAP ABAP基础语法-Excel上传(十)
EXCEL BDS模板上传及赋值 上传模板事务代码:OAER l 功能代码:向EXCEL模板中写入数据示例代码如下 REPORT ZEXCEL_DOI. “doi type pools TYPE-POOLS: soi. *SAP Desktop Office Integration Interfaces DATA: container TYPE REF TO cl_gui_custom_c…...
记录一次某某虚拟机的逆向
导语 学了一段时间的XPosed,发现XPosed真的好强,只要技术强,什么操作都能实现... 这次主要记录一下我对这款应用的逆向思路 apk检查 使用MT管理器检查apk的加壳情况 发现是某数字的免费版本 直接使用frida-dexdump 脱下来后备用 应用分…...
upload-labs关卡7(基于黑名单的空格绕过)通关思路
文章目录 前言一、回顾上一关知识点二、靶场第七关通关思路1、看源代码2、空格绕过3、检查文件是否成功上传 总结 前言 此文章只用于学习和反思巩固文件上传漏洞知识,禁止用于做非法攻击。注意靶场是可以练习的平台,不能随意去尚未授权的网站做渗透测试…...
CnosDB 在最近新发布的 2.4.0 版本中增加对时空函数的支持。
CnosDB 在最近新发布的 2.4.0 版本中增加对时空函数的支持。 概述 时空函数是一种用于描述时空结构和演化的函数。它在物理学、数学和计算机科学等领域中都有广泛的应用。时空函数可以描述物体在时空中的位置、速度、加速度以及其他相关属性。 用法 CnosDB 将使用一种全新的…...
python实现炒股自动化,个人账户无门槛量化交易的开始
本篇作为系列教程的引子,对股票量化程序化自动交易感兴趣的朋友可以关注我,现在只是个粗略计划,后续会根据需要重新调整,并陆续添加内容。 股票量化程序化自动交易接口 很多人在找股票个人账户实现程序化自动交易的接口࿰…...
推荐系统笔记--Swing模型的原理
1--Swing模型的引入 在 Item CF 召回中,物品的相似度是基于其受众的交集来衡量的,但当受众的交集局限在一个小圈子时,就会误将两个不相似的物品定义为相似; Swing 模型引入用户的重合度来判断两个用户是否属于一个小圈子ÿ…...
联想小新Pro14默认设置的问题
联想小新Pro14 锐龙版,Win11真的挺多不习惯的,默认配置都不符合一般使用习惯。 1、默认人走过自动开机。人机互动太强了; 2、默认短超时息屏但不锁屏,这体验很容易觉得卡机然后唤起,却又不用密码打开; 3…...
【洛谷 P5019】[NOIP2018 提高组] 铺设道路 题解(分治算法+双指针)
[NOIP2018 提高组] 铺设道路 题目背景 NOIP2018 提高组 D1T1 题目描述 春春是一名道路工程师,负责铺设一条长度为 n n n 的道路。 铺设道路的主要工作是填平下陷的地表。整段道路可以看作是 n n n 块首尾相连的区域,一开始,第 i i i …...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
