设计模式之原型模式:深入浅出讲解对象克隆

在这里插入图片描述

~犬📰余~

“我欲贱而贵,愚而智,贫而富,可乎?
曰:其唯学乎”

原型模式概述

在我们的日常生活中,经常会遇到"复制"这样的场景。比如我们在准备文件时,常常会复印一份原件;或者在手机上长按某个应用图标,可以快速创建一个完全相同的快捷方式。原型模式就是这样一种设计模式,它提供了一种通过复制现有对象来创建新对象的方式。
原型模式的核心思想是:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。如在Java中调用一个对象的clone()方法来获得该对象的副本。通过这种方式,我们可以隐藏复制对象的复杂性,提供一个统一的创建接口。

原型模式的组成

原型模式主要包含以下两个角色:

  • Prototype(原型接口):这是一个声明克隆方法的接口。在Java中,我们通常是通过实现Cloneable接口并重写Object类的clone()方法来实现。它就像是一个复印机的标准操作手册,规定了如何进行复制操作。
  • ConcretePrototype(具体原型类):实现了Prototype接口的具体类型,它们必须实现clone()方法。就像是可以被复印的具体文件,负责执行实际的复制操作。

浅拷贝和深拷贝

在理解原型模式时,最关键的是要弄清楚浅拷贝(Shallow Copy)和深拷贝(Deep Copy)的区别。
在这里插入图片描述

浅拷贝的实现与特点

浅拷贝是Java中默认的拷贝方式。当我们调用Object类的clone()方法时,会创建一个新对象,并将原对象中的基本类型字段值直接复制到新对象,而对于引用类型字段,则复制引用而不是创建新的对象。让我们看一个例子:

public class Employee implements Cloneable {
        private String name;
        private Department department;  // 引用类型

        public Employee(String name, Department department) {
            this.name = name;
            this.department = department;
        }

        @Override
        public Employee clone() throws CloneNotSupportedException {
            return (Employee) super.clone();
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Department getDepartment() {
            return department;
        }

        public void setDepartment(Department department) {
            this.department = department;
        }
    }

    public class Department {
        private String name;

        public Department(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

下面编写测试方法:

 public void test() {
        Employee employee = new Employee("1", new Department("1"));
        try {
            Employee clone = employee.clone();
            clone.setName("2");
            clone.getDepartment().setName("2");
            System.out.println(employee.getName() + " " + employee.getDepartment().getName());
            System.out.println(clone.getName() + " " + clone.getDepartment().getName());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }

测试结果:
在这里插入图片描述
在这个例子中,如果我们克隆一个Employee对象,新对象会有自己的name字段(String虽然是引用类型,但Java对其进行了特殊处理,表现得像基本类型),但department字段仍然指向原对象的Department实例。这就意味着,如果我们修改拷贝对象的department的属性,原对象的department也会跟着改变。

深拷贝的实现方式

要实现深拷贝,我们需要确保对象中的所有引用类型字段也被复制。实现深拷贝主要有两种方式:

1.递归克隆:

public class Employee implements Cloneable {
    private String name;
    private Department department;
    
    @Override
    public Employee clone() throws CloneNotSupportedException {
        Employee cloned = (Employee) super.clone();
        // 深拷贝:克隆引用类型字段
        cloned.department = this.department.clone();
        return cloned;
    }
}

public class Department implements Cloneable {
    private String name;
    
    @Override
    public Department clone() throws CloneNotSupportedException {
        return (Department) super.clone();
    }
}

2.序列化方式:

public class Employee implements Serializable {
    private String name;
    private Department department;
    
    public Employee deepCopy() {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (Employee) ois.readObject();
        } catch (Exception e) {
            return null;
        }
    }
}

深拷贝确保了对象的完全独立性,克隆对象的修改不会影响原对象。这在处理复杂对象结构时特别重要,比如在游戏中复制一个包含多个装备的角色,或者在文档编辑器中复制一个包含多个图层的图形对象。
但需要注意的是,深拷贝也有其成本:它需要递归地复制所有关联对象或是需要进行额外的序列化与反序列化操作,这会消耗更多的内存和计算资源。因此,在选择使用浅拷贝还是深拷贝时,需要根据具体场景和需求来权衡。

原型模式优缺点

原型模式作为一种创建型设计模式,具有其独特的优势和局限性。理解这些特点对于正确使用原型模式至关重要。

  • 优点:原型模式首先提供了一种快速创建对象的方法。当对象的创建过程比较复杂,比如需要经过繁琐的初始化,或者需要访问数据库、文件系统时,使用原型模式可以显著提高性能。其次,原型模式提供了一种隔离复杂对象创建过程的方法,让客户端代码与具体类的实现细节解耦。这样,客户端只需要知道如何克隆一个现有对象,而不需要了解创建的细节。
  • 缺点:实现深拷贝时,如果对象的结构比较复杂,包含多层嵌套的引用类型,就需要编写较为复杂的克隆代码。另外,对于那些包含循环引用的对象(比如对象A中包含对象B的引用,对象B中又包含对象A的引用),使用原型模式可能会导致较大的开销,甚至可能出现死循环。

在使用原型模式时,建议先评估对象的结构复杂度和创建成本。如果对象结构简单,或者创建成本不高,直接使用new关键字可能是更好的选择。但如果对象的创建成本较高,或者需要经常创建相似对象,那么使用原型模式就是一个不错的选择。

原型模式的适用场景

  • 在游戏开发中,当我们需要创建大量相似的游戏对象时,原型模式就非常有用。比如在一个射击游戏中,子弹、敌人、道具这些对象都会频繁创建,它们的基本属性和行为都是相似的,只是位置、速度等参数不同。这时使用原型模式,我们可以预先创建好这些对象的模板,然后通过克隆来快速生成新的实例。
  • 在文档编辑器中,当用户需要复制一个复杂的文档对象时,这个文档可能包含文本、图片、表格等多种元素。使用原型模式可以方便地创建文档的副本,同时保持所有元素的格式和样式。
  • 在处理大型配置对象时,比如数据库连接池的配置,这些配置对象通常包含大量的参数和复杂的嵌套结构。当需要创建多个相似的配置时,使用原型模式可以避免重复的初始化过程,同时也能确保配置的一致性。

总结

原型模式为我们提供了一种灵活且高效的对象创建方式,它通过复制现有对象来创建新对象,而不是从零开始构建。通过本文的讲解,我们了解了原型模式的核心思想、角色组成,以及浅拷贝和深拷贝的区别。
在实际应用中,选择使用浅拷贝还是深拷贝是一个关键决策点。对于简单对象,浅拷贝通常就足够了;但对于包含复杂引用关系的对象,可能需要实现深拷贝来确保对象的完全独立性。
需要注意的是,原型模式并不是银弹。它特别适合那些创建成本高、但结构相对稳定的对象。在使用时,要注意权衡性能和复杂度,选择最适合当前场景的实现方式。同时,也要注意处理好克隆过程中可能出现的异常情况,确保代码的健壮性。

在这里插入图片描述

关注犬余,共同进步

技术从此不孤单

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

集合ArrayList

黑马程序员Java的个人笔记 BV17F411T7Ao p111~p115 目录 集合存储数据类型的特点 创建对象 ArrayList 成员方法 .add 增加元素 .remove 删除元素 .set 修改元素 .get 查询元素 .size 获取长度 基本数据类型对应的包装类 Character 练习 返回多个数据 集合存储…

day10性能测试(2)——Jmeter安装环境+线程组+Jmeter参数化

【没有所谓的运气🍬,只有绝对的努力✊】 目录 1、LoadRunner vs Jmeter 1.1 LoadRunner 1.2 Jmeter 1.3 对比小结 2、Jmeter 环境安装 2.1 安装jdk 2.2 安装Jmeter 2.3 小结 3、Jmeter 文件目录结构 4、Jmeter默认配置修改 5、Jmeter元件、组…

【全连接神经网络】核心步骤及其缺陷

前向传播 计算公式(其中一种) x1/x2:输入值,一般是神经网络上一层的输出或者输入数据本身,上图中表示两个节点w11 w13:权重,在神经网络中,权重是学习的参数,表示每个输入…

自荐一部IT方案架构师回忆录

作者本人毕业于一个不知名大专院校,所读专业计算机科学技术。2009年开始IT职业生涯,至今工作15年。擅长TSQL/Shell/linux等技术,曾经就职于超万人大型集团、国内顶级云厂商、央国企公司。参与过运营商大数据平台、大型智慧城市ICT、云计算、人…

【密码学】SM4算法

一、 SM4算法简介 SM4算法是中国国家密码管理局于2012发布的一种分组密码算法,其官方名称为SMS4(SMS4.0),相关标准为GM/T 0002-2012《SM4分组密码算法》。SM4算法的分组长度和密钥长度均为128比特,采用非平衡Feistel结构。采用32…

番外篇 | 关于YOLOv8网络结构中添加注意力机制的常见方法 | Neck网络

前言:Hello大家好,我是小哥谈。注意力机制是一种神经网络模型,它通过赋予输入不同的权重的处理方式,来使得模型对输入信息的处理更加关注重要的部分。注意力机制在自然语言处理、计算机视觉等领域中得到了广泛的应用。🌈 目录 🚀1.基础概念 🚀2.案例说明 案例…

有序集合ZSET【Redis对象篇】

🏆 作者简介:席万里 ⚡ 个人网站:https://dahua.bloggo.chat/ ✍️ 一名后端开发小趴菜,同时略懂Vue与React前端技术,也了解一点微信小程序开发。 🍻 对计算机充满兴趣,愿意并且希望学习更多的技…

JSON语法、序列化/反序列化、(JS、JSON、Java对象间转换)、fastjson库、JS内置对象JSON

目录 一、JSON基础。 (1)什么是JSON? (2)JSON对象语法。 1、数据结构。 2、键与值的格式。 3、JSON对象在线解析与格式验证网址。 4、JSON对象格式的完整示例。 二、序列化与反序列化。 (1)序列…

C#中的string操作详解-截取、分割、连接、替换等

在C#中,string 类提供了许多用于操作字符串的方法,包括截取、分隔和连接等。以下是一些常用字符串操作的介绍和实例: 1. 截取字符串 Substring 方法 用于从字符串中截取子字符串。 语法: //从startIndex开始截取,…

STOP: 0x0000007B

STOP: 0x0000007B 安装电脑,提示出错,硬盘模型错误,SATA模式3种:AHCI、IDE、RAID 高级这个图好像漏了,下次补吧,就在高级里面硬盘模式修改下

echarts自定义仪表盘样式及一些属性了解

目录 一、自定义仪表盘 1.仪表盘相关 2.常用属性 (1)series (2)graphic 二、自定义仪表盘 1.基本仪表盘绘制 2.分析结构,分别绘制 (1)自定义形状 (2)仪表盘各部…

图神经网络代码学习—基本使用与分类任务

初步接触图神经网络代码 环境配置 对于在多目标跟踪中应用图匹配网络,需要学习使用GNN图神经网络,对于图神经网络的实现需要学习使用一下库和项目来进行实践。 PyG(PyTorch Geometric)是一个建立在 PyTorch 基础上的库&#xf…

操作系统:死锁与饥饿

目录 死锁概念 饥饿与饿死概念 饥饿和死锁对比 死锁类型 死锁条件(Coffman条件) 死锁恢复方法 死锁避免 安全状态与安全进程序列: 银行家算法: 死锁检测时机(了解): 死锁检测 死锁案…

SkyWalking Helm Chart 4.7.0 安装、配置

https://skywalking.apache.org/events/release-apache-skywalking-kubernetes-helm-chart-4.7.0/https://github.com/apache/skywalking-helm/tree/v4.7.0https://skywalking.apache.org/zh/2020-04-19-skywalking-quick-start/简介 skywalking 是分布式系统的 APM(Applicat…

electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题

electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题 这篇文章是接我cocos专栏的上一篇文章继续写的,我上一篇文章写的是 cocos 开发触摸屏项目,需要嵌入一个网页用来展示,最后通过 electron 打包成 exe 程序,而且网页里面…

嵌入式Linux应用开发中CAN通信实现

14.1 CAN介绍 14.1.1 CAN是什么? CAN,全称为“Controller Area Network”,即控制器局域网,是国际上应用最广泛的现场总线之一。最初,CAN 被设计作为汽车环境中的微控制器通讯,在车载各电子控制装置 ECU 之间交换信息,形成汽车电子控制网络。比如:发动机管理系统、变速…

Grafana功能菜单介绍

Grafana的功能菜单设计为侧边栏(sidebar)形式,可以折叠隐藏,便于我们更加专注数据的可视化。现将菜单栏各项功能进行编号讲解,如下图所示:① Grafana Logo 在这里插入图片描述 点击Grafana的logo,无论当前处于哪个页面,都会跳转回Home Page(主页)。② 新建与导入用于…

MVC基础——市场管理系统(二)

文章目录 项目地址三、Produtcts的CRUD3.1 Products列表的展示页面(Read)3.1.1 给Product的Model里添加Category的属性3.1.2 View视图里展示Product List3.2 增加Product数据(Add)3.2.1 创建ViewModel用来组合多个Model3.2.2 在_ViewImposts里引入ViewModels3.2.3 添加Add的…

前端 mp4 视频改成 m3u8 流模式

前端 mp4 视频改成 m3u8 流模式 mp4 视频的问题 1、mp4 视频通常对应一个文件,播放时需要加载全部文件,消耗网络资源。如果用户从中间某个时间访问,也会从头开始下载,浪费服务器性能。 2、mp4 视频文件容易被用户下载到本地。有…

爬虫基础之代理的基本原理

在做爬虫的过程中经常会遇到一种情况,就是爬虫最初是正常运行、正常抓取数据的,一切看起来都是那么美好,然而一杯茶的工夫就出现了错误,例如 403 Forbidden,这时打开网页一看,可能会看到“您的IP访问频率太…