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

创建型(四) - 原型模式

一、概念

原型模式(Prototype Pattern):利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。

使用场景:如果对象的创建成本比较大,而且同一个类的不同对象之间差别不大(大部分字段都相同),这种情况下可以考虑原型模式。

二、实现

原型模式有两种实现方法,深拷贝和浅拷贝。

  • 浅拷贝:只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对象的引用对象。
  • 深拷贝:得到的是一份完完全全独立新的对象。

当一个类中只有基本数据类型时,浅拷贝与深拷贝是同样的。
当一个类中含有引用数据类型是,浅拷贝只是拷贝一份引用,修改浅拷贝的值,原来的也会跟着变化。

举个例子:
肯德基套餐A对象,包含一个可乐对象,一个汉堡包对象。
浅拷贝:就是复制了一份肯德基套餐A,但是里面包含的可乐和汉堡还是原来的那一份,如果咬一口汉堡,那么原来的那个就缺一块。
浅拷贝.png

深拷贝:也是复制了一份肯德基套餐A,但是里面的可乐和汉堡是新的对象,如果咬一口汉堡,那么原来的那个还是完好无损的。
深拷贝.PNG

  • 浅拷贝实现:

代码:注意如果想实现克隆功能,要克隆的类要实现Cloneable 接口。
1、肯德基套餐A

public class KFCSetMenuA implements Cloneable {private float price;private Cola cola;private Hamburger hamburger;....省略set和get方法@Overrideprotected Object clone() {KFCSetMenuA kfcSetMenuA = null;try {kfcSetMenuA = (KFCSetMenuA) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();System.out.println(e.toString());}return kfcSetMenuA;}
}

2、其他对象

public class Cola implements Cloneable {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}public class Hamburger implements Cloneable {}

3、实现浅拷贝

    public static void main(String[] args) throws CloneNotSupportedException {KFCSetMenuA kfcSetMenuA = new KFCSetMenuA();kfcSetMenuA.setPrice(15.5f);Cola cola = new Cola();cola.setName("可口可乐");kfcSetMenuA.setCola(cola);KFCSetMenuA cloneKFCSetMenuA = (KFCSetMenuA) kfcSetMenuA.clone();cloneKFCSetMenuA.setPrice(16.5f);cloneKFCSetMenuA.getCola().setName("百事可乐");System.out.println("原对象可乐:" + kfcSetMenuA.getCola().getName());System.out.println("克隆对象可乐:" + cloneKFCSetMenuA.getCola().getName());System.out.println("原对象价格:" + kfcSetMenuA.getPrice());System.out.println("克隆对象价格:" + cloneKFCSetMenuA.getPrice());}

4、浅拷贝结果
浅拷贝结果.png

总结:从结果看到,说明克隆后的对象和原始的指向的是同一个cola对象,改名字后都变了,但是基本类型数据是没有改变的。

  • 深拷贝实现方式1

1、重新定义Cola中的clone方法。

public class Cola implements Cloneable {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@NonNull@Overrideprotected Object clone() throws CloneNotSupportedException {Cola cola = null;try {cola = (Cola) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();System.out.println(e.toString());}return cola;}
}

2、实现的时候同时把Cola对象clone一遍。

    public static void main(String[] args) throws CloneNotSupportedException {KFCSetMenuA kfcSetMenuA = new KFCSetMenuA();kfcSetMenuA.setPrice(15.5f);Cola cola = new Cola();cola.setName("可口可乐");kfcSetMenuA.setCola(cola);KFCSetMenuA cloneKFCSetMenuA = (KFCSetMenuA) kfcSetMenuA.clone();//克隆Cola对象Cola cloneCola = (Cola) cola.clone();cloneKFCSetMenuA.setCola(cloneCola);cloneKFCSetMenuA.setPrice(16.5f);cloneKFCSetMenuA.getCola().setName("百事可乐");System.out.println("原对象可乐:" + kfcSetMenuA.getCola().getName());System.out.println("克隆对象可乐:" + cloneKFCSetMenuA.getCola().getName());System.out.println("原对象价格:" + kfcSetMenuA.getPrice());System.out.println("克隆对象价格:" + cloneKFCSetMenuA.getPrice());}

3、深拷贝实现方式1结果:
深拷贝结果.png
总结:这个方式就是把克隆对象中引用的对象也进行浅克隆,但是如果出现嵌套多层的时候,每个引用对象都得实现克隆,太麻烦。

  • 深拷贝实现方式2-序列化

1、在KFCSetMenuA 类中加入如下方法,并且KFCSetMenuA 要实现Serializable接口。

public KFCSetMenuA deepClone() {//声明流对象ByteArrayOutputStream bos = null;ByteArrayInputStream bis = null;ObjectOutputStream oos = null;ObjectInputStream ois = null;try {//创建序列化流bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);//将当前对象以对象流的方式输出oos.writeObject(this);//创建反序化流bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);//将流对象反序列化,实现类的深拷贝。return (KFCSetMenuA) ois.readObject();} catch (Exception e) {e.printStackTrace();return null;} finally {try {//关闭资源bos.close();bis.close();oos.close();ois.close();} catch (IOException e) {e.printStackTrace();}}}

2、实现方式

public static void main(String[] args) throws CloneNotSupportedException {KFCSetMenuA kfcSetMenuA = new KFCSetMenuA();kfcSetMenuA.setPrice(15.5f);Cola cola = new Cola();cola.setName("可口可乐");kfcSetMenuA.setCola(cola);// 序列化深拷贝KFCSetMenuA cloneKFCSetMenuA = kfcSetMenuA.deepClone();cloneKFCSetMenuA.setPrice(16.5f);cloneKFCSetMenuA.getCola().setName("百事可乐");System.out.println("原对象可乐:" + kfcSetMenuA.getCola().getName());System.out.println("克隆对象可乐:" + cloneKFCSetMenuA.getCola().getName());System.out.println("原对象价格:" + kfcSetMenuA.getPrice());System.out.println("克隆对象价格:" + cloneKFCSetMenuA.getPrice());}

3、深拷贝实现方式2结果:
深拷贝序列化结果.png

参考文章:
极客时间《设计模式》(王争)

相关文章:

创建型(四) - 原型模式

一、概念 原型模式(Prototype Pattern):利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。 使用场景:如果对象的创建成本比较大…...

ABAP 定义复杂的数据结构

最近有个需求是实现ABAP数据类型与JASON类型的转换。想要创建个ABAP的数据类型来接JASON类型是个挺麻烦的事。例如下面这个JASON数据,是个很简单的数据结构。但对ABAP来说有4层了,就有点复杂了。 不过ABAP的数据类型也是支持直接定义数据结构的嵌套的。如…...

HCIP第四节-----------------------------BGP

一、BGP基础 1、BGP得概述 (1)、AS OSPF、IS-IS等IGP路由协议在组织机构网络内部广泛应用,随着网络规模扩大,网络中路由数量不断增长,IGP已无法管理大规模网络,AS的概念由此诞生。 AS指的是在同一个组织…...

Temu闯关日韩受挫?跨境电商卖家如何打磨好营销链路

海外版拼多多 Temu 先后在日本和韩国上线,然而效果不似预期,日韩市场对这套“低价补贴”策略并不买账。作为一个尚未被日韩消费者熟悉的网站,其价格之便宜无法让消费者信任。除此之外更大的问题是,在日本卷不过线下零售与百元店&a…...

console的几个常用用法

console.log() 其一、主要表示:向 Web 控制台输出一条消息; 其二、而具体是什么信息就以传递的实参为准,然后就是在控制台就能显示自己传递参数的结果; console.log([1,3,5,7]) // 输出 [1, 3, 5, 7] console.log({}) // 输出 {} conso…...

服务器数据恢复-HP EVA存储VDISK被删除的数据恢复案例

服务器数据恢复环境: 某单位有一台HP EVA存储,连接2组扩展柜,扩展柜中有12块FATA磁盘和10块FC磁盘,不确定数量的LUN,主机安装WINDOWS SERVER操作系统,存储设备用来存放该单位的重要资料。 服务器故障初检&…...

(搜索) 剑指 Offer 13. 机器人的运动范围 ——【Leetcode每日一题】

❓剑指 Offer 13. 机器人的运动范围 难度:中等 地上有一个 m 行 n 列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外)&…...

Java并发编程之线程池详解

目录 🐳今日良言:不悲伤 不彷徨 有风听风 有雨看雨 🐇一、简介 🐇二、相关代码 🐼1.线程池代码 🐼2.自定义实现线程池 🐇三、ThreadPoolExecutor类 🐳今日良言:不悲伤 不彷徨 有风听风 有…...

开源数据库Mysql_DBA运维实战 (总结)

开源数据库Mysql_DBA运维实战 (总结) SQL语句都包含哪些类型 DDL DCL DML DQL Yum 安装MySQL的配置文件 配置文件:/etc/my.cnf日志目录:/var/log/mysqld.log错误日志:/var/log/mysql/error.log MySQL的主从切换 查看主…...

图神经网络与分子表征:1. 分子图和图神经网络基础

CSDN的朋友们大家好,好久没写系列文章了。 近期读了很多图神经网络(GNN)和分子表征(molecular representation)的论文,正好最近不是很忙,所以我决定把自己的学习过程记录下来,与大家…...

Spring Boot与Redisson的整合。分布式锁

Spring Boot与Redisson的整合可以帮助您在Spring Boot应用程序中使用分布式锁、缓存等功能。下面是一些基本步骤来整合Spring Boot与Redisson: 添加Maven/Gradle依赖: 在您的Spring Boot项目的pom.xml(Maven)或build.gradle&#…...

Lua中逻辑运算符and,or,not 区别与用法

在Lua中,逻辑运算符包括 and、or 和 not。它们用于对布尔值进行逻辑运算。 and运算符: 当同时满足两个表达式时,返回第二个表达式的值;否则,返回第一个表达式的值。如果第一个表 达式的值为false或nil,则…...

使用 spaCy 增强 NLP 管道

介绍 spaCy 是一个用于自然语言处理 (NLP) 的 Python 库。SpaCy 的 NLP 管道是免费且开源的。开发人员使用它来创建信息提取和自然语言理解系统,例如 Cython。使用该工具进行生产,拥有简洁且用户友好的 API。 如果您处理大量文本,您会想了解更多相关信息。例如,它是关于什…...

【HCIP】08.ISIS中间系统

链路状态协议,传递LSA信息ISIS基于数据链路层封装在OSI时,也有自己的网络层地址和自己的路由协议,即ISIS。之前的ISIS支持OSI的网络层地址,是为OSI中的CLNP(无连接网络协议)网络设计的路由协议,…...

Android 13 Framework 添加自定义的系统服务CustomService

目的: 添加自定义的系统服务,在自定义的服务中开发定制的API接口和功能,独立于系统核心服务,方便开发和维护。 开发环境:Android 13 MTK平台 涉及修改的文件如下 device/mediatek/sepolicy/base/private/service_contexts device/mediatek/sepolicy/base/vendor/platfo…...

前端食堂技术周刊第 95 期:Fresh 1.4、Rollup 迁移至 SWC计划、RSC Devtools、使用开源库的边界、AI 帮你讲论文

美味值:🌟🌟🌟🌟🌟 口味:冰葡美式 食堂技术周刊仓库地址:https://github.com/Geekhyt/weekly 大家好,我是童欧巴。欢迎来到前端食堂技术周刊,我们先来看下…...

【TypeScript】枚举类型

在 TypeScript 中,枚举(Enum)是一种用于定义命名常量集合的数据类型。枚举使代码更加可读和可维护,因为它们为一组具有语义的值提供了命名。 以下是 TypeScript 中枚举的基本用法和特点: // 声明一个枚举 enum Direc…...

快速通过华为HCIP认证

你可以按照以下步骤进行准备和学习: 华为认证课程和资料--提取码:1234https://pan.baidu.com/s/1YJhD8QbocHhZ30MvrKm8hg 了解认证要求:查看华为官方网站上的HCIP认证要求和考试大纲,了解考试的内容、考试形式和考试要求。 学习相关知识&am…...

派森 #P124. 公式计算

描述 输入数正整数m,输出0! 1! ...m!的计算结果。 样例 输入 5 输出 154 代码: m int(input()) result 1 factorial 1 for i in range(1, m 1):factorial * iresult factorial print(result) # 法2def factorial(n):"""计…...

opencv进阶14-Harris角点检测-cv2.cornerHarris

类似于人的眼睛和大脑,OpenCV可以检测图像的主要特征并将这 些特征提取到所谓的图像描述符中。然后,可以将这些特征作为数据 库,支持基于图像的搜索。此外,我们可以使用关键点将图像拼接起 来,组成更大的图像。&#x…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

【位运算】消失的两个数字(hard)

消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...