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

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...