当前位置: 首页 > 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: 三级医院评审标准(…...

【原创】Mac mini M1安装home-brew

Mac mini M1 所需神器 home-brew 按照官网的脚本无法安装。 无奈&#xff0c;从github下载安装包来安装。 Homebrew 结果&#xff0c;还需要先安装 Xcode command 命令行工具 xcode-select --install安装完了&#xff0c;却无法执行。 修改配置文件 cd vi .zshrc添加如下内…...

【python交互界面】实现动态观察图像在给定HSV范围的区域显示

HSV颜色空间 与RGB颜色空间相比&#xff0c;HSV颜色空间更适合进行颜色分析和提取特定颜色的目标。在HSV空间中&#xff0c;颜色信息被分布在不同的通道上&#xff0c;使我们能够更准确地定义颜色的范围&#xff0c;并使用阈值操作轻松地分离出我们感兴趣的区域部分。 HSV三个通…...

Vue3中定义变量是选择ref还是reactive?

目录 ref和reactive的优势 1. ref 优势&#xff1a; 应用场景&#xff1a; 示例&#xff1a; 2. reactive 优势&#xff1a; 应用场景&#xff1a; 示例&#xff1a; ref和reactive的劣势 1. ref 2. reactive 应用案例 总结 Vue3中定义变量可以选择使用ref或reac…...

数据结构 | 查漏补缺之哈希表、最短路径、二叉树与森林的转换

哈希表是什么&#xff1f; 或者说 设图采用邻接表的存储结构&#xff0c;写对图的删除顶点和删除边的算法步骤 删除边 删除点 最短路径问题 参考博文 迪杰斯特拉(Dijkstra)算法_dijkstra算法-CSDN博客 Dijkstra(迪杰斯特拉&#xff09;算法 定义一个点为源点&#xff0c;算源…...

SpringCloud

五大组件 注册/配置中心 Nacos 、Eureka远程调用 Feign负载均衡 Ribbon服务保护 sentinel&#xff08;实现限流、降级、熔断&#xff09;网关 gateway 注册中心 Eureka 服务注册&#xff1a;服务提供者把自己的信息注册到Eureka&#xff0c;由Eureka来保存这些信息服务发现…...

fastadmin嵌套关联查询,thinkPHP5嵌套关联查询

fastadmin嵌套关联查询 thinkPHP5嵌套关联查询 笔记记录 嵌套关联查询 A -> B -> C A 表关联B表 B表关联C表 同时把A&#xff0f;B&#xff0f;C表相关的数据展现出来 B表的model B表关联C表 我的C表是B表的自身关联。也是一个表&#xff0c;所以为C表 namespace app…...

Power BI - 5分钟学习拆分列

每天5分钟&#xff0c;今天介绍Power BI拆分列功能。 什么是拆分列&#xff1f; 有时导入Power BI的数据表中&#xff0c;某列内容都包含同样的特殊字符如 /&/-/_等&#xff0c;可以利用这个特殊字符进行拆分列的操作&#xff0c;获得我们想要的信息。 操作举例&#xf…...

ELK(四)—els基本操作

目录 elasticsearch基本概念RESTful API创建非结构化索引&#xff08;增&#xff09;创建空索引&#xff08;删&#xff09;删除索引&#xff08;改&#xff09;插入数据&#xff08;改&#xff09;数据更新&#xff08;查&#xff09;搜索数据&#xff08;id&#xff09;&…...

【100天精通Python】Day75:Python机器学习-第一个机器学习小项目_鸾尾花分类项目(上)

目录 1 机器学习中的Helloworld _鸾尾花分类项目 2 导入项目所需类库和鸾尾花数据集 2.1 导入类库 2.2 scikit-learn 库介绍 &#xff08;1&#xff09;主要特点&#xff1a; &#xff08;2&#xff09;常见的子模块&#xff1a; 3 导入鸾尾花数据集 3.1 概述数据 3.…...

gitlab高级功能之容器镜像仓库

今天给大家介绍一个gitlab的高级功能 - Container Registry&#xff0c;该功能可以实现docker镜像的仓库功能&#xff0c;将gitlab上的代码仓的代码通过docker构建后并推入到容器仓库中&#xff0c;好处就是无需再额外部署一套docker仓库。 文章目录 1. 参考文档2. Container R…...