创建型(四) - 原型模式

一、概念

原型模式(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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/53430.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【IO进程线程】使用标准IO函数完成用户的登录和注册

1 实现登录功能 自定义一个usr.txt,先手动输入其账户密码。 格式:账户 密码 例: zhangsan 12345 lisi abcde wangwu abc123 需求如下: 1. 从终端获取账户密码,与文件中的账户密码比较; 2. 若终端输入的账户…

商城-学习整理-高级-商城业务-Sentinel限流熔断降级Sleuth+Zipkin链路追踪(二十二)

目录 一、秒杀系统的架构二、SpringCloud Alibaba-Sentinel简介1、熔断降级限流什么是熔断什么是降级异同:什么是限流 2、Sentinel 简介官方文档:Sentinel 具有以下特征:Sentinel 分为两个部分: 3、Hystrix 与 Sentinel 比较4、整合 FeignSentinel 测试熔…

微服务集成spring cloud sentinel

目录 1. sentinel使用场景 2. sentinel组成 3. sentinel dashboard搭建 4. sentinel客户端详细使用 4.1 引入依赖 4.2 application.properties增加dashboard注册地址 4.3 手动增加限流配置类 4.4 rest接口及service类 4.5 通过dashboard动态配置限流规则 1. sentinel使…

Vue3项目实战

目录 一、项目准备 二、基础语法应用 2.1、mixin应用 2.2、网络请求 2.3、显示与隐藏 2.4、编程式路由跳转 2.5、下载资料 2.6、调用方法 2.7、监听路由变化 2.8、pinia应用 (1)存储token(user.js) (2)全选全不选案例(car.js) 一、项目准备 下载: cnp…

[JavaWeb]【十三】web后端开发-原理篇

目录 一、SpringBoot配置优先级 1.1 配置优先级比较 1.2 java系统属性和命令行参数 1.3 打包运行jar 1.4 综合优先级​编辑 二、Bean管理 2.1 获取bean 2.2 bean作用域 2.2.1 五种作用域 2.2.2 配置作用域 2.3 第三方bean 2.3.1 编写公共配置类 三、SpringBoot原理 …

mybatis-plus如何使用枚举类来实现性别和标签的数字带描述

文章目录 目录 文章目录 前言 一、环境准备 二、使用步骤 一 实体类 二 枚举类 三 持久层 四 控制层 总结 前言 枚举是一种表示一组有限可能取值的数据类型。它具有以下几个好处: 易于理解和维护:枚举提供了一种清晰明了的方式来表示一组具体的取值&a…

SpringBoot定时器调度

导入依赖 <dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId></dependency> 对方法添加注解 Scheduled(cron "*/2 * * * * ?") public void scheduledMethod() { // 设…

【Linux操作系统】线程的基本知识和创建--循环创建多个子线程

本篇文章主要介绍了线程的概念和作用&#xff0c;线程三级映射的实现&#xff0c;创建线程的方法&#xff08;讲解pthread_self和pthread_create函数&#xff09;&#xff0c;循环创建多个子线程为例子&#xff0c;同时分析线程之间的全局变量的共享问题&#xff0c;希望可以帮…

Redis笔记——(狂神说)待续

Nosql概述 为什么要用NoSql&#xff1f; 1、单机mysql的年代&#xff1a;90年代&#xff0c;网站访问量小&#xff0c;很多使用静态网页html写的&#xff0c;服务器没压力。 当时瓶颈是&#xff1a;1)数据量太大一个机器放不下。2)数据的索引(BTree)&#xff0c;一个机器内存也…

Git最简入门

文章目录 几个基本概念版本控制Git的由来分布式 vs 集中式GitSVN Git、GitHub、GitLab、GitWeb、Gitee的区别 动手进行版本控制初始化Git使用情景一&#xff1a;开发新项目使用情景二&#xff1a;在已有项目上开发设置代理 参考 几个基本概念 版本控制 在工作学习中&#xff…

LiveData相关基本使用及去除黏性数据的方法

目录 一、LiveData的基本使用1. 使用方式一2. 使用方式二3. 使用方式三 二、LiveData 去除黏性数据的方法1. 去除黏性的Java版本2. 去除黏性的Kotlin版本 一、LiveData的基本使用 1. 使用方式一 MyLiveData.kt package com.example.mylivedata.simple1import androidx.lifec…

「Python|音视频处理|环境准备」如何在Windows系统下安装并配置音视频处理工具FFmpeg

本文主要介绍如何在Windows系统下安装并配置音视频处理工具FFmpeg&#xff0c;方便使用python进行音视频相关的下载或编辑处理。 文章目录 一、下载软件二、解压并配置三、验证安装 一、下载软件 首先要去 ffmpeg官网 下载软件包 由于上面直接下载的按钮是.tar.xz格式的。为了…

Pygame编程(8)image模块

Pygame编程&#xff08;8&#xff09;image模块 函数示例 函数 pygame.image.load 从文件&#xff08;或类似文件的对象&#xff09;加载新图像load(filename) -> Surfaceload(fileobj, namehint“”) -> Surface pygame.image.save 将图像保存到文件&#xff08;或类似…

基于 Alpine 环境源码构建 alibaba-tengine(阿里巴巴)的 Docker 镜像

About Alpine&#xff08;简介&#xff09; Alpine Linux 是一款极其轻量级的 Linux 发行版&#xff0c;基于 busybox&#xff0c;多被当做 Docker 镜像的底包&#xff08;基础镜像&#xff09;&#xff0c;在使用容器时或多或少都会接触到此系统&#xff0c;本篇文章我们以该镜…

Pydev·离线git包

Pydev离线git包 1.下载离线git包&#xff1a;eclipse.egit.repository-4.4.0.201606070830-r.zip 2.将解压后目录&#xff1a;eclipse.egit.repository-4.4.0.201606070830-r\plugins下的jar文件放到 ide\eclipse\plugins目录下 3.重启pydevIDE 百度搜索站长工具&#xff1a;h…

head 请求了解过吗?如何用 get 模拟 head 请求?不需要服务器返回数据,怎么实现?

HEAD请求是HTTP/1.1协议中定义的一个请求方法&#xff0c;与GET请求相似&#xff0c;但只请求目标URL的头部&#xff0c;不请求实际的数据或者说正文内容。其主要用途是&#xff1a; 检查资源是否存在。获取资源的元数据&#xff08;如响应头中的Content-Length或Last-Modifie…

Spring集成【MyBatis】和【PageHelper分页插件】整合---详细介绍

一&#xff0c;spring集成Mybatis的概念 Spring 整合 MyBatis 是将 MyBatis 数据访问框架与 Spring 框架进行集成&#xff0c;以实现更便捷的开发和管理。在集成过程中&#xff0c;Spring 提供了许多特性和功能&#xff0c;如依赖注入、声明式事务管理、AOP 等 它所带来给我们的…

校对的力量:当专业遇上细节,文字焕发新生

在这个信息爆炸的时代&#xff0c;文字成为了我们传达思想、展现形象的重要工具。从新闻稿、政府材料到商业文档&#xff0c;其背后的准确性和专业性往往决定了信息传递的效果。而保证这一切的&#xff0c;就是细致入微的校对工作。 1.错别字与校对&#xff1a;细节之美 错别字…

go web框架 gin-gonic源码解读03————middleware

go web框架 gin-gonic源码解读03————middleware&#xff08;context&#xff09; 今天打完游戏有空整理整理之前看的gin的中间件设计&#xff0c;go的中间件设计相较于前两站还是蛮简单&#xff0c;蛮容易看懂的&#xff0c;所以顺便把context也一起写一下。 中间件是现在w…