当前位置: 首页 > news >正文

原型模式(Prototype Pattern)

1 基本概念

1.1 大佬文章

设计模式是什么鬼(原型)

详解设计模式:原型模式-腾讯云开发者社区-腾讯云


1.2 知识汇总

(1)原型模式:先 new 一个实例,该实例符合需求,之后再根据这个实例为原型,重复构建新的对象;
(2)所属类型:创建型模式
(3)作用:重复创建对象;
(4)优点:可以重复获得对象的同时保持较高的性能;

1.3 基本构成

(1)抽象原型类:抽象原型类是定义具有克隆自己的方法接口,是所有具体原型类的公共父类,可以是抽象类,也可以是接口;在 Java 中 Cloneable 接口可以看作是抽象原型类;
(2)具体原型类:根据这个类可以获得一个原型对象,并且这个类中需要重现 clone 方法,可以根据这个 clone 方法复制对象;
(3)访问类:使用具体原型类中的 clone 方法,可以不断重复的复制对象;

2 Java 中的克隆

根据现有的对象复制一个新的对象的操作就是克隆,Java 中克隆分为浅克隆和深克隆(我个人更喜欢说浅拷贝和深拷贝);浅拷贝和深拷贝的区别主要在重写 clone 方法上有所区别;但是,虽然之前有了解过拷贝的相关问题,但是发今天发现其实这里面还是有一些细节需要注意的。

2.1 拷贝的必要条件

(1)实现 Cloneable 接口:这个接口其实是一个标记接口,想要使用 clone 方法,就必须先实现这个接口,否则该类的 clone 方法是不可用的。

(2)重写 clone 方法:仅仅实现 Cloneable 接口还不能达到要求,还需要重写这个方法,否则依然不能使用 clone 方法;

2.2 浅拷贝

浅拷贝是将某个对象的所有成员属性都赋值给 clone 得到的对象;
(1)简单数据类型,如 int 等等的数据类型,直接将值拷贝过去;
(2)非简单数据类型,如引用类型的数据,是将引用的地址赋值给拷贝得到的对象,也就是说并没有新建一个成员对象,而是简单的将引用复制一遍;

package se.wangs.clonedemo.pojo;/*** -- coding: UTF-8 -- *** @author wangs* @date 2023/12/6 9:07* @description 演示浅拷贝*/
public class Teacher {private String name;private String idNo;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getIdNo() {return idNo;}public void setIdNo(String idNo) {this.idNo = idNo;}
}
package se.wangs.clonedemo.pojo;/*** -- coding: UTF-8 -- *** @author wangs* @date 2023/12/6 9:08* @description 演示clone*/
public class Student implements Cloneable{private String idNo;private String name;private Teacher teacher;public String getIdNo() {return idNo;}public void setIdNo(String idNo) {this.idNo = idNo;}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;}@Overridepublic Student clone() {try {Student clone = (Student) super.clone();// TODO: copy mutable state here, so the clone can't change the internals of the originalreturn clone;} catch (CloneNotSupportedException e) {throw new AssertionError();}}
}
package se.wangs.clonedemo;import se.wangs.clonedemo.pojo.Student;
import se.wangs.clonedemo.pojo.Teacher;/*** -- coding: UTF-8 -- *** @author wangs* @date 2023/12/4 16:37* @description 浅拷贝*/
public class ShallowClone {public static void main(String[] args) {Teacher teacher1 = new Teacher();teacher1.setIdNo("001");teacher1.setName("teacher_001");Student student1 = new Student();student1.setIdNo("101");student1.setName("student_101");student1.setTeacher(teacher1);Student cloneStudent = student1.clone();System.out.println("---------------------------");System.out.println(student1);System.out.println("idNo = " + student1.getIdNo());System.out.println("name = " + student1.getName());System.out.println("teacher = " + student1.getTeacher());System.out.println("---------------------------");System.out.println(cloneStudent);System.out.println("idNo = " + cloneStudent.getIdNo());System.out.println("name = " + cloneStudent.getName());System.out.println("teacher = " + cloneStudent.getTeacher());}
}

运行测试类得到的结果如下:

---------------------------
se.wangs.clonedemo.pojo.Student@41629346
idNo = 101
name = student_101
teacher = se.wangs.clonedemo.pojo.Teacher@214c265e
---------------------------
se.wangs.clonedemo.pojo.Student@448139f0
idNo = 101
name = student_101
teacher = se.wangs.clonedemo.pojo.Teacher@214c265e

说明:

  • student1:原对象
  • cloneStudent:浅拷贝得到的对象

可以看到,student 中有一个引用类型的成员变量 teacher,浅拷贝得到的 cloneStudent 中的 teacher 变量与 student1 指向的对象相同;

2.3 深拷贝

深拷贝就是会将引用类型的变量做进一步处理,clone 出的对象的引用数据类型的成员变量,会指向一个新的变量

package se.wangs.clonedemo.pojo;/*** -- coding: UTF-8 -- *** @author wangs* @date 2023/12/6 9:07* @description 演示浅拷贝*/
public class Teacher implements Cloneable{private String name;private String idNo;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getIdNo() {return idNo;}public void setIdNo(String idNo) {this.idNo = idNo;}@Overridepublic Teacher clone() {try {Teacher clone = (Teacher) super.clone();// TODO: copy mutable state here, so the clone can't change the internals of the originalreturn clone;} catch (CloneNotSupportedException e) {throw new AssertionError();}}
}
package se.wangs.clonedemo.pojo;/*** -- coding: UTF-8 -- *** @author wangs* @date 2023/12/6 9:08* @description 演示clone*/
public class Student implements Cloneable{private String idNo;private String name;private Teacher teacher;public String getIdNo() {return idNo;}public void setIdNo(String idNo) {this.idNo = idNo;}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;}@Overridepublic Student clone() {try {Student clone = (Student) super.clone();// 获得原来的 teacher 对象,并clone出一个新的teacher对象Teacher newTeacher = clone.getTeacher().clone();// 重新设置teacherclone.setTeacher(newTeacher);return clone;} catch (CloneNotSupportedException e) {throw new AssertionError();}}
}
package se.wangs.clonedemo;import se.wangs.clonedemo.pojo.Student;
import se.wangs.clonedemo.pojo.Teacher;/*** -- coding: UTF-8 -- *** @author wangs* @date 2023/12/6 10:09* @description 深拷贝*/
public class DeepClone {public static void main(String[] args) {Teacher teacher1 = new Teacher();teacher1.setIdNo("001");teacher1.setName("teacher_001");Student student1 = new Student();student1.setIdNo("101");student1.setName("student_101");student1.setTeacher(teacher1);Student cloneStudent = student1.clone();System.out.println("---------------------------");System.out.println(student1);System.out.println("idNo = " + student1.getIdNo());System.out.println("name = " + student1.getName());System.out.println("teacher = " + student1.getTeacher());System.out.println("---------------------------");System.out.println(cloneStudent);System.out.println("idNo = " + cloneStudent.getIdNo());System.out.println("name = " + cloneStudent.getName());System.out.println("teacher = " + cloneStudent.getTeacher());}
}

运行得到

---------------------------
se.wangs.clonedemo.pojo.Student@41629346
idNo = 101
name = student_101
teacher = se.wangs.clonedemo.pojo.Teacher@214c265e
---------------------------
se.wangs.clonedemo.pojo.Student@448139f0
idNo = 101
name = student_101
teacher = se.wangs.clonedemo.pojo.Teacher@7cca494b

可以看到,得到的 teacher 对象的地址变了;

2.4 总结

浅拷贝和深拷贝的主要区别就是对引用类型的变量的处理
(1)浅拷贝:引用类型的变量拷贝前后指向同一个对象;
(2)深拷贝:引用类型的变量拷贝后指向新的对象;
(3)核心:重写 clone 方法时对引用类型变量的处理不同;
参考资料:
Java深入理解深拷贝和浅拷贝区别_java深拷贝浅拷贝-CSDN博客


3 原型设计模式

3.1 设计模式体验

(1)抽象原型类:Cloneable 接口
(2)具体原型类:可以 new 原型实例,实现 Cloneable 接口,重写了 clone() 方法;

package se.wangs.prototype;/*** -- coding: UTF-8 -- *** @author wangs* @date 2023/12/6 9:07* @description*/
public class Teacher implements Cloneable{private String name;private String idNo;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getIdNo() {return idNo;}public void setIdNo(String idNo) {this.idNo = idNo;}@Overridepublic Teacher clone() {try {Teacher clone = (Teacher) super.clone();// TODO: copy mutable state here, so the clone can't change the internals of the originalreturn clone;} catch (CloneNotSupportedException e) {throw new AssertionError();}}
}
package se.wangs.prototype;/*** -- coding: UTF-8 -- *** @author wangs* @date 2023/12/6 9:08* @description 具体原型类*/
public class Student implements Cloneable{private String idNo;private String name;private Teacher teacher;public String getIdNo() {return idNo;}public void setIdNo(String idNo) {this.idNo = idNo;}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;}@Overridepublic Student clone() {try {Student clone = (Student) super.clone();// 获得原来的 teacher 对象,并clone出一个新的teacher对象Teacher newTeacher = clone.getTeacher().clone();// 重新设置teacherclone.setTeacher(newTeacher);return clone;} catch (CloneNotSupportedException e) {throw new AssertionError();}}
}

(3)访问类:实例化原型,通过 clone 复制原型对象;

package se.wangs.prototype;/*** -- coding: UTF-8 -- *** @author wangs* @date 2023/12/6 10:30* @description 访问类*/
public class Client {public static void main(String[] args) {Teacher teacher = new Teacher();teacher.setName("okay");teacher.setIdNo("0001");Student student = new Student();student.setIdNo("stu_001");student.setName("onesun");student.setTeacher(teacher);System.out.println("---------------------------");System.out.println(student);System.out.println("idNo = " + student.getIdNo());System.out.println("name = " + student.getName());System.out.println("teacher = " + student.getTeacher());for (int i = 0; i < 10; i++) {System.out.println("---------------------------");Student cloneStudent = student.clone();System.out.println(cloneStudent);System.out.println("idNo = " + cloneStudent.getIdNo());System.out.println("name = " + cloneStudent.getName());System.out.println("teacher = " + cloneStudent.getTeacher());}}
}

3.2 总结

(1)原型设计模式的思想就是拿到一个对象,将该对象当作一个标准,然后使用 clone 方法不断重复的去复制这个标准(原型对象),从而得到大量同类型的对象,在游戏等等场景中应用广泛。
(2)使用原型模式而不是 new 对象的优点是,节约 new 需要消耗的资源,提高系统的性能。
(3)原型模式的应用
Spring 框架对 bean 对象进行管理,而默认的 bean 对象是单例模式的,也可以使用 scope 属性指定为非单例模式,当 scope 属性为"socpe=prototype"时,就是非单例模式,其实这里使用的就是原型模式;

相关文章:

原型模式(Prototype Pattern)

1 基本概念 1.1 大佬文章 设计模式是什么鬼&#xff08;原型&#xff09; 详解设计模式&#xff1a;原型模式-腾讯云开发者社区-腾讯云 1.2 知识汇总 &#xff08;1&#xff09;原型模式&#xff1a;先 new 一个实例&#xff0c;该实例符合需求&#xff0c;之后再根据这个实…...

IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket

文章目录 1. 引言2. 短轮询&#xff08;Short Polling&#xff09;2.1 原理2.2 代码示例2.2.1 服务器端&#xff08;Node.js&#xff09;2.2.2 客户端&#xff08;HTML JavaScript&#xff09; 3. 长轮询&#xff08;Long Polling&#xff09;3.1 原理3.2 代码示例3.2.1 服务器…...

04_W5500_TCP_Server

上一节我们完成了TCP_Client实验&#xff0c;这节使用W5500作为服务端与TCP客户端进行通信。 目录 1.W5500服务端要做的&#xff1a; 2.代码分析&#xff1a; 3.测试&#xff1a; 1.W5500服务端要做的&#xff1a; 服务端只需要打开socket&#xff0c;然后监听端口即可。 2…...

入门Redis学习总结

记录之前刚学习Redis 的笔记&#xff0c; 主要包括Redis的基本数据结构、Redis 发布订阅机制、Redis 事务、Redis 服务器相关及采用Spring Boot 集成Redis 实现增删改查基本功能 一&#xff1a;常用命令及数据结构 1.Redis 键(key) # 设置key和value 127.0.0.1:6379> set …...

SpringSecurity6 | 自定义登录页面

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…...

从单向链表中删除指定值的节点

输入一个单向链表和一个节点的值&#xff0c;从单向链表中删除等于该值的节点&#xff0c;删除后如果链表中无节点则返回空指针。 链表的值不能重复。构造过程&#xff0c;例如输入一行数据为:6 2 1 2 3 2 5 1 4 5 7 2 2则第一个参数6表示输入总共6个节点&#xff0c;第二个参数…...

Vue2与Vue3的语法对比

Vue2与Vue3的语法对比 Vue.js是一款流行的JavaScript框架&#xff0c;通过它可以更加轻松地构建Web用户界面。随着Vue.js的不断发展&#xff0c;Vue2的语法已经在很多应用中得到了广泛应用。而Vue3于2020年正式发布&#xff0c;带来了许多新的特性和改进&#xff0c;同时也带来…...

实时动作识别学习笔记

目录 yowo v2 yowof 判断是在干什么,不能获取细节信息 yowo v2 https://github.com/yjh0410/YOWOv2/blob/master/README_CN.md ModelClipmAPFPSweightYOWOv2-Nano1612.640ckptYOWOv2-Tiny...

5G常用简称

名称缩写全称非周期 信道状态信息参考信号aperidoc CSIAperidoc Channel State Information缓冲区状态报告BSRBuffer Status Report小区特定无线网络标识CS-RNTICell-Specific Radio Network Temporary Identifier主小区组MCGMaster Cell groupMCG的节点MNMasternode主小区PCel…...

自动化测试框架性能测试报告模板

一、项目概述 1.1 编写目的 本次测试报告&#xff0c;为自动化测试框架性能测试总结报告。目的在于总结我们课程所压测的目标系统的性能点、优化历史和可优化方向。 1.2 项目背景 我们公开课的性能测试目标系统。主要是用于我们课程自动化测试框架功能的实现&#xff0c;以及…...

【SpringBoot】解析Springboot事件机制,事件发布和监听

解析Springboot事件机制&#xff0c;事件发布和监听 一、Spring的事件是什么二、使用步骤2.1 依赖处理2.2 定义事件实体类2.3 定义事件监听类2.4 事件发布 三、异步调用3.1 启用异步调用3.2 监听器方法上添加 Async 注解 一、Spring的事件是什么 Spring的事件监听&#xff08;…...

华为ensp实验——基于全局地址池的DHCP组网实验

目录 前言实验目的实验内容实验结果 前言 该实验基于华为ensp&#xff0c;版本号是1.3.00.100 V100R003C00SPC100&#xff0c;只供学习和参考&#xff0c;不作任何商业用途。 具体的DHCP命令可以看系列文章链接&#xff0c;计算机网络实验&#xff08;华为eNSP模拟器&#xff…...

如何选择一款安全可靠的跨网安全数据交换系统?

随着网络和数据安全的重视程度增加&#xff0c;为了有效地保护内部的核心数据资产&#xff0c;普遍会采用内外网隔离的策略。像国内的政府机构、金融、能源电力、航空航天、医院等关乎国计民生的行业和领域均已进行了网络的隔离&#xff0c;将内部划分成不同的网段&#xff0c;…...

基于c++版本的数据结构改-python栈和队列思维总结

##栈部分-&#xff08;叠猫猫&#xff09; ##抽象数据类型栈的定义&#xff1a;是一种遵循先入后出的逻辑的线性数据结构。 换种方式去理解这种数据结构如果我们在一摞盘子中取到下面的盘子&#xff0c;我们首先要把最上面的盘子依次拿走&#xff0c;才可以继续拿下面的盘子&…...

算法通关村第七关—迭代实现二叉树的遍历(黄金)

迭代实现二叉树的遍历 迭代法实现前序遍历 前序遍历是中左右&#xff0c;如果还有左子树就一直向下找。完了之后再返回从最底层逐步向上向右找。不难写出如下代码&#xff1a;&#xff08;注意代码中&#xff0c;空节点不入栈&#xff09; public List<Integer>preorde…...

Java期末复习题之封装

点击返回标题->23年Java期末复习-CSDN博客 第1题. 定义一个类Person,定义name和age私有属性&#xff0c;定义有参的构造方法对name和age进行初始化。在测试类中创建该类的2个对象&#xff0c;姓名、年龄分别为lili、19和lucy、20&#xff0c;在屏幕打印出2个对象的姓名和年龄…...

湖科大计网:计算机网络概述

一、计算机网络的性能指标 一、速率 有时候数据量也认为是以10为底的&#xff0c;看怎么好算。&#xff08;具体吉大考试用什么待商榷&#xff09; 二、带宽 在模拟信号系统中带宽的含义&#xff0c;本课程中用到的地方是&#xff1a;香农定理和奈奎斯特定理公式的应用之中。 …...

每日一道c语言

任务描述 题目描述:输入10个互不相同的整数并保存在数组中&#xff0c;找到该最大元素并删除它&#xff0c;输出删除后的数组 相关知识&#xff08;略&#xff09; 编程要求 请仔细阅读右侧代码&#xff0c;结合相关知识&#xff0c;在Begin-End区域内进行代码补充&#xf…...

(C)一些题11

1. #include<stdio.h> #include<string.h> void main() { char *s1"ABCDEF"&#xff0c;*s2"aB"&#xff1b; s1; s2; puts(s1)&#xff1b; puts(s2)&#xff1b; printf("%d\n",strcmp(s1,s2))&#xff1b; } 答案&#xff1…...

多级路由component页面不加载

项目基于vue-element-admin 新建SubView.vue <template><router-view /> </template><script setup> </script>在父层添加component {path: /sj,component: Layout,redirect: /sj,name: 三级医院评审标准(2022),meta: {title: 三级医院评审标准(…...

【DeepSeek数据隐私保护终极指南】:20年安全专家亲授5大合规落地实践与3大避坑红线

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;DeepSeek数据隐私保护的核心理念与演进脉络 DeepSeek自诞生以来&#xff0c;将“数据主权归用户、模型能力不以隐私让渡为前提”确立为不可妥协的底层信条。其隐私保护理念并非静态规范&#xff0c;而是随技术…...

灾变瞬间生成人员分布图,为抢险决策提供可靠依据 ——视频孪生智能态势研判矿山抢险决策技术方案

灾变瞬间生成人员分布图&#xff0c;为抢险决策提供可靠依据——视频孪生智能态势研判矿山抢险决策技术方案一、方案引言煤矿井下瓦斯爆炸、顶板垮塌、透水突涌等灾害具备瞬时爆发、连锁破坏、环境骤变的典型特征。险情发生短短数分钟内&#xff0c;巷道结构受损变形、供电通信…...

使用 Node.js 和 Taotoken 为博客网站快速搭建一个智能内容摘要生成接口

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 使用 Node.js 和 Taotoken 为博客网站快速搭建一个智能内容摘要生成接口 对于个人博客站长而言&#xff0c;为篇幅较长的文章提供一…...

UnityExplorer自由视角相机完整指南:突破游戏视角限制的终极方案

UnityExplorer自由视角相机完整指南&#xff1a;突破游戏视角限制的终极方案 【免费下载链接】UnityExplorer An in-game UI for exploring, debugging and modifying IL2CPP and Mono Unity games. 项目地址: https://gitcode.com/gh_mirrors/un/UnityExplorer UnityEx…...

从‘黑客工具’到‘运维神器’:我是如何在Linux日常运维中用Netcat替代Telnet和Nmap的

从‘黑客工具’到‘运维神器’&#xff1a;Netcat在Linux日常运维中的五大实战场景如果你在运维领域摸爬滚打多年&#xff0c;一定遇到过这样的窘境&#xff1a;需要快速检查某个服务端口是否开放&#xff0c;却发现telnet没安装&#xff1b;想扫描几个常用端口&#xff0c;nma…...

Sketch MeaXure:现代化设计标注解决方案如何革命性提升团队协作效率与开发质量

Sketch MeaXure&#xff1a;现代化设计标注解决方案如何革命性提升团队协作效率与开发质量 【免费下载链接】sketch-meaxure 项目地址: https://gitcode.com/gh_mirrors/sk/sketch-meaxure 执行摘要 Sketch MeaXure作为基于TypeScript重构的Sketch插件&#xff0c;为企…...

Mac Mouse Fix技术架构深度解析:如何通过系统级事件拦截实现鼠标功能增强

Mac Mouse Fix技术架构深度解析&#xff1a;如何通过系统级事件拦截实现鼠标功能增强 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix 在macOS生…...

ComfyUI-VideoHelperSuite深度解析:高级视频合成与批量处理技术

ComfyUI-VideoHelperSuite深度解析&#xff1a;高级视频合成与批量处理技术 【免费下载链接】ComfyUI-VideoHelperSuite Nodes related to video workflows 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-VideoHelperSuite 在AI驱动的视频创作工作流中&#xff…...

忘记压缩包密码怎么办?3个步骤帮你快速找回加密文件访问权限

忘记压缩包密码怎么办&#xff1f;3个步骤帮你快速找回加密文件访问权限 【免费下载链接】ArchivePasswordTestTool 利用7zip测试压缩包的功能 对加密压缩包进行自动化测试密码 项目地址: https://gitcode.com/gh_mirrors/ar/ArchivePasswordTestTool 你是否曾经面对一个…...

jdk1.7 HashMap为什么会出现死循环

JDK 1.7 的 HashMap出现死循环的条件 JDK 1.7 的 HashMap 在多线程并发环境下&#xff0c;如果同时触发扩容操作&#xff0c;就可能会因为其采用的头插法机制而产生一个环形链表&#xff0c;导致程序在调用 get() 等方法时陷入死循环。 JDK 1.7的HashMap在设计上并非线程安全&a…...