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

news2024/12/12 14:59:09

在这里插入图片描述

~犬📰余~

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

原型模式概述

在我们的日常生活中,经常会遇到"复制"这样的场景。比如我们在准备文件时,常常会复印一份原件;或者在手机上长按某个应用图标,可以快速创建一个完全相同的快捷方式。原型模式就是这样一种设计模式,它提供了一种通过复制现有对象来创建新对象的方式。
原型模式的核心思想是:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。如在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关键字可能是更好的选择。但如果对象的创建成本较高,或者需要经常创建相似对象,那么使用原型模式就是一个不错的选择。

原型模式的适用场景

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

总结

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

在这里插入图片描述

关注犬余,共同进步

技术从此不孤单

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

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

相关文章

Elasticsearch Serverless 中的数据流自动分片

作者:来自 Elastic Andrei Dan 在 Elastic Cloud Serverless 中,我们根据索引负载自动为数据流配置最佳分片数量,从而使用户无需摆弄分片。 传统上,用户会更改数据流的分片配置,以处理各种工作负载并充分利用可用资源。…

【Golang】Go语言编程思想(六):Channel,第四节,Select

使用 Select 如果此时我们有多个 channel,我们想从多个 channel 接收数据,谁来的快先输出谁,此时应该怎么做呢?答案是使用 select: package mainimport "fmt"func main() {var c1, c2 chan int // c1 and …

MindSearch深度解析实践

任务要求:在 官方的MindSearch页面 复制Spaces应用到自己的Spaces下,Space 名称中需要包含 MindSearch 关键词,请在必要的步骤以及成功的对话测试结果当中 1.在github codespace中配置环境 conda create -n mindsearch python3.10 -y conda…

【PyQt5教程 二】Qt Designer 信号与槽的使用方法及PyQt5基本小部件说明

目录 一、信号与槽机制: 二、信号与槽使用方法: (1)使用Qt Designer 的信号与槽编辑器: (2)使用固定语法直接建立信号槽连接: 三、PyQt小部件及其触发信号: &#x…

基于PHP课堂签到系统的设计与实现

摘 要 随着教育业的迅速发展和学生人数的不断增加,导致在班级登记制度中传统的“点到”方式不能适应学校的实际需要。从而需要设计一个好的课堂签到系统将会对课堂签到管理工作带来事半功倍的效果。文章着重介绍了基于实践应用的班级签到系统的开发流程&#xff0c…

CSS学习记录11

CSS布局 - display属性 display属性是用于控制布局的最终要的CSS属性。display 属性规定是否/如何显示元素。每个HTML元素都有一个默认的display值,具体取决于它的元素类型。大多数元素的默认display值为block 或 inline。 块级元素(block element&…

高效利用资源:分布式有状态服务的高可靠性设计

在分布式系统设计中,实现有状态服务的高可靠性通常采用主备切换的方式。当主服务停止工作时,备服务接管任务,例如通过Keepalive实现VIP的切换以保证可用性。然而,这种方式存在资源浪费的问题,因为备服务始终处于空转状…

重生之我在异世界学智力题(2)

大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 本文目录 引言智力题:逃离孤岛智力题&a…

论文浅尝 | SAC-KG:利用大语言模型作为领域知识图谱熟练的自动化构造器(ACL2024)...

笔记整理:杜超超,天津大学硕士,研究方向为自然语言处理、大语言模型 论文链接:https://aclanthology.org/2024.acl-long.238/ 发表会议:ACL 2024 1. 动机 知识图谱(KG)在各个专业领域的知识密集…

Python机器视觉的学习

一、二值化 1.1 二值化图 二值化图:就是将图像中的像素改成只有两种值,其操作的图像必须是灰度图。 1.2 阈值法 阈值法(Thresholding)是一种图像分割技术,旨在根据像素的灰度值或颜色值将图像分成不同的区域。该方法…

Elasticsearch高性能实践

前言 本方案主要从运维层面分析es是实际生产使用过程中的参数优化,深入理解es各个名词及含义,深入分析es的使用过程中应注意的点,详细解释参数设置的原因以及目的,主要包括系统层面,参数层面。除此之外,优…

笔记本外接显示屏没声音

1、笔记本正常有声音,但是外接显示屏后没有声音了怎么回事呢?原来外接显示屏后笔记本的声音输出会自动选择显示屏的音频输出,但是显示屏可能没有声音输出所以导致笔记本没有声音。 2、解决办法:打开笔记本设置,选择声…

JavaWeb学习(4)(四大域、HttpSession原理(面试)、SessionAPI、Session实现验证码功能)

目录 一、web四大域。 (1)基本介绍。 (2)RequestScope。(请求域) (3)SessionScope。(会话域) (4)ApplicationScope。(应用域) (5)PageScope。(页面域) 二、Ht…

用人话讲计算机:Python篇!(十二)正则运算+re模块

目录 一、正则表达式 (1)什么是正则表达式 (2)它的结构及使用 示例: 1.字符 . (←这里有个小点哦) 2.字符 | 3.字符 [ ] 4.字符^ 5.字符\d (3)补充&#xff…

力扣打卡12:复原IP地址

链接:93. 复原 IP 地址 - 力扣(LeetCode) 这道题需要对字符串进行操作,我选择了三层循环,其实还可以递归。 我在循环时进行了剪枝,比如一些情况直接跳出循环。 我的代码: class Solution { p…

说下JVM中一次完整的GC流程?

大家好,我是锋哥。今天分享关于【说下JVM中一次完整的GC流程?】面试题。希望对大家有帮助; 说下JVM中一次完整的GC流程? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在JVM中,垃圾回收(GC&am…

vs配置c++标准

在 vcxproj 文件中添加 <LanguageStandard>stdcpp17</LanguageStandard> 和在 Visual Studio 属性页面中设置 “C语言标准” 为 “ISO C17 标准 (/std:c17)” 是完全等价的。 它们的对应关系是&#xff1a; VS属性页面中的设置&#xff1a; 项目 -> 属性 ->…

TcpServer 服务器优化之后,加了多线程,对心跳包进行优化

TcpServer 服务器优化之后&#xff0c;加了多线程&#xff0c;对心跳包进行优化 TcpServer.h #ifndef TCPSERVER_H #define TCPSERVER_H#include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <vector> #include <map> #…

风控大讲堂|游戏黑产情报挖掘与治理

您的产品有没有遇到过被薅羊毛了&#xff1f;网络游戏行业的繁荣&#xff0c;催生了一批围绕游戏而生的职业玩家&#xff0c;他们利用多开、修改器等手段&#xff0c;疯狂薅游戏资源&#xff0c;破坏游戏经济平衡&#xff0c;给游戏公司带来了难以估量的巨大损失。那么针对此类…

最近邻搜索 - 经典树型结构 M-Tree

前言 如果你对这篇文章感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 最近邻搜索的目标是从 N N N 个对象中&#xff0c;快速找到距离查询点最近的对象。根据需求的不同&#xff0c;该任务又分…