全网最简单的Java设计模式【九】原型模式深入解析

如果觉得本文能够帮到您,请关注🌟、点赞👍、收藏📚,让这份美好延续下去!

一、引言

在 Java 软件开发中,设计模式起着至关重要的作用,它们为解决各种常见的软件设计问题提供了经过验证的方案。其中,原型模式是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而无需了解对象的具体创建过程。这种模式在很多场景下都非常有用,尤其是当对象的创建过程较为复杂或者创建成本较高时。本文将深入探讨 Java 设计模式中的原型模式,包括其定义、实现方式、优缺点以及应用场景,并通过具体的代码示例进行详细说明。

二、原型模式的定义

原型模式(Prototype Pattern)是一种创建对象的方式,通过复制一个已经存在的实例来创建新的实例,而不是通过传统的构造函数来创建。这样可以避免一些复杂的对象初始化过程,提高对象创建的效率。在原型模式中,被复制的对象称为原型对象,新创建的对象称为克隆对象。

三、原型模式的实现方式

在 Java 中,原型模式可以通过两种方式实现:浅克隆(Shallow Clone)和深克隆(Deep Clone)。

(一)浅克隆实现

1. 假设我们有一个包含 基本数据类型引用类型的类

package com.jsglxx.design.prototype;import java.util.List;class Person implements Cloneable {private int age;private List<String> hobbies;public Person(int age, List<String> hobbies) {this.age = age;this.hobbies = hobbies;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public List<String> getHobbies() {return hobbies;}public void setHobbies(List<String> hobbies) {this.hobbies = hobbies;}@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}
}

2. 使用示例:

package com.jsglxx.design.prototype;import java.util.ArrayList;
import java.util.List;public class ShallowCloneExample {public static void main(String[] args) {try {List<String> hobbies = new ArrayList<>();hobbies.add("Reading");Person original = new Person(30, hobbies);Person clone = (Person) original.clone();System.out.println("Original: Age = " + original.getAge() + ", Hobbies = " + original.getHobbies());System.out.println("Clone: Age = " + clone.getAge() + ", Hobbies = " + clone.getHobbies());// 修改原始对象的引用类型字段内容original.getHobbies().add("Drawing");original.setAge(35);System.out.println("After modification:");System.out.println("Original: Age = " + original.getAge() + ", Hobbies = " + original.getHobbies());System.out.println("Clone: Age = " + clone.getAge() + ", Hobbies = " + clone.getHobbies());} catch (CloneNotSupportedException e) {e.printStackTrace();}}
}

3. 输出结果:

Original: Age = 30, Hobbies = [Reading]
Clone: Age = 30, Hobbies = [Reading]
After modification:
Original: Age = 35, Hobbies = [Reading, Drawing]
Clone: Age = 30, Hobbies = [Reading, Drawing]

在这个浅克隆示例中:

  • 首先创建了一个原始对象 original,其中包含一个基本数据类型 age 和一个引用类型 hobbies 列表。当通过 super.clone() 进行浅克隆创建 clone 对象时,基本数据类型 age 被按值复制,所以原始对象和克隆对象的 age 是独立的。
  • 然而,对于引用类型 hobbies 列表,浅克隆只是复制了引用,这意味着原始对象和克隆对象中的 hobbies 指向同一个列表对象。
  • 当修改原始对象的 hobbies 列表内容(添加 “Drawing”)以及修改 age 为 35 时,由于克隆对象的 hobbies 引用与原始对象相同,所以克隆对象的 hobbies 列表也会显示添加后的内容。而克隆对象的 age 虽然在克隆时与原始对象相同,但由于基本数据类型是按值复制,所以不会随原始对象的修改而改变。

(二)深克隆示例

1. 为了实现深克隆,可以使用序列化的方式:

package com.jsglxx.design.prototype.deep;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.List;class Person implements Serializable {private static final long serialVersionUID = 1L;private int age;private List<String> hobbies;public Person(int age, List<String> hobbies) {this.age = age;this.hobbies = hobbies;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public List<String> getHobbies() {return hobbies;}public void setHobbies(List<String> hobbies) {this.hobbies = hobbies;}public Person deepClone() {try {ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(this);ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);return (Person) ois.readObject();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();return null;}}
}

2. 使用示例:

package com.jsglxx.design.prototype.deep;import java.util.ArrayList;
import java.util.List;public class DeepCloneExample {public static void main(String[] args) {try {List<String> hobbies = new ArrayList<>();hobbies.add("Reading");Person original = new Person(30, hobbies);Person clone = original.deepClone();System.out.println("Original: Age = " + original.getAge() + ", Hobbies = " + original.getHobbies());System.out.println("Clone: Age = " + clone.getAge() + ", Hobbies = " + clone.getHobbies());// 修改原始对象的引用类型字段内容original.getHobbies().add("Drawing");original.setAge(35);System.out.println("After modification:");System.out.println("Original: Age = " + original.getAge() + ", Hobbies = " + original.getHobbies());System.out.println("Clone: Age = " + clone.getAge() + ", Hobbies = " + clone.getHobbies());} catch (Exception e) {e.printStackTrace();}}
}

在这个深克隆示例中,

  1. 通过序列化的方式进行深克隆。首先将原始对象序列化为字节流,然后再从字节流中反序列化出一个新的对象作为克隆对象。
  2. 对于基本数据类型 age,其行为与浅克隆类似,被按值复制,所以原始对象和克隆对象的 age 是独立的。
  3. 对于引用类型 hobbies 列表,在深克隆过程中,实际上创建了一个新的列表对象,并将原始列表中的内容复制到新列表中。这意味着原始对象和克隆对象的 hobbies 列表是完全独立的两个对象。
  4. 当修改原始对象的 hobbies 列表内容(添加 “Drawing”)以及修改 age 为 35 时,由于克隆对象的 hobbies 列表是独立的新对象,所以不会受到原始对象修改的影响。而克隆对象的 age 也同样不会随原始对象的修改而改变。

四、原型模式的优缺点

(一)优点

  1. 性能优化:原型模式通过复制现有对象来创建新对象,避免了复杂的对象初始化过程,从而提高了对象创建的效率。特别是对于创建成本较高的对象,如需要大量计算或占用大量资源的对象,原型模式可以显著提高性能。
  2. 简化对象创建过程:在某些情况下,对象的创建过程可能非常复杂,需要多个步骤和大量的参数。使用原型模式可以将这些复杂的创建过程封装在原型对象中,通过复制原型对象来创建新对象,从而简化了对象创建的过程。
  3. 提供灵活性:原型模式允许在运行时动态地创建对象,并且可以根据需要修改原型对象,从而创建出不同的克隆对象。这种灵活性使得原型模式在一些需要动态创建对象的场景下非常有用,如用户界面开发、游戏开发等。

(二)缺点

  1. 违背开闭原则:为了实现原型模式,需要为每个类都提供一个clone()方法或者实现Serializable接口,这可能会导致代码的可维护性降低。特别是当需要修改类的结构时,可能需要同时修改clone()方法或者序列化过程,这违背了开闭原则。
  2. 深克隆实现复杂:深克隆需要复制对象及其引用的所有对象,这可能会导致实现复杂。特别是对于复杂的对象结构,深克隆可能需要递归地复制所有的引用对象,这可能会导致性能问题和代码的复杂性增加。
  3. 处理循环引用困难:如果对象之间存在循环引用,即一个对象引用了另一个对象,而另一个对象又引用了第一个对象,那么在进行深克隆时可能会出现问题。处理循环引用需要特殊的算法和技术,这可能会增加代码的复杂性。

五、原型模式的应用场景

(一)资源密集型对象创建

当创建对象的成本较高时,如需要大量计算、占用大量内存或需要访问外部资源等,可以使用原型模式来提高性能。通过复制已经存在的对象,可以避免重复的计算和资源访问,从而提高创建对象的效率。

例如,在图形绘制软件中,创建一个复杂的图形对象可能需要大量的计算和内存。如果每次需要绘制这个图形时都重新创建一个对象,将会非常耗时和耗资源。使用原型模式,可以将已经创建好的图形对象作为原型,通过复制原型来创建新的图形对象,从而提高绘制效率。

(二)复杂对象复制

当需要复制一个复杂的对象结构时,使用原型模式可以简化复制过程。通过复制原型对象,可以避免手动复制每个子对象的繁琐过程,并且可以确保复制的准确性。

例如,在一个游戏开发中,角色对象可能包含多个属性和子对象,如位置、速度、装备等。如果需要复制一个角色对象,可以使用原型模式来复制整个角色对象及其所有的子对象,从而确保复制的准确性和完整性。

(三)动态对象创建

在一些需要动态创建对象的场景下,如用户界面开发、游戏开发等,可以使用原型模式来提供灵活性。通过修改原型对象,可以创建出不同的克隆对象,从而满足不同的需求。

例如,在一个用户界面开发中,可能需要根据用户的选择动态地创建不同类型的窗口或控件。使用原型模式,可以将不同类型的窗口或控件作为原型,通过复制原型来创建新的窗口或控件,从而满足用户的需求。

六、总结

原型模式是一种非常有用的设计模式,它允许通过复制现有对象来创建新对象,从而提高对象创建的效率和灵活性。在 Java 中,可以通过浅克隆和深克隆两种方式实现原型模式。浅克隆只复制对象的基本数据类型字段和引用类型字段的引用,而深克隆则会复制对象及其引用的所有对象。原型模式具有性能优化、简化对象创建过程和提供灵活性等优点,但也存在违背开闭原则、深克隆实现复杂和处理循环引用困难等缺点。在实际应用中,需要根据具体情况选择合适的实现方式,并注意处理可能出现的问题。

🌟 对技术管理感兴趣 请关注下方 ⬇ 【 技术管理修行】

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

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

相关文章

【AIGC】ChatGPT提示词Prompt精确控制指南:Scott Guthrie的建议详解与普通用户实践解析

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;斯科特古斯里&#xff08;Scott Guthrie&#xff09;的建议解读人机交互设计的重要性减轻用户认知负担提高Prompt的易用性结论 &#x1f4af;普通用户视角的分析普通用户…

MySQL(2)【库的操作】

阅读导航 引言一、创建数据库1. 基本语法2. 创建数据库案例&#x1f4cc;创建名为db1的数据库&#x1f4cc;创建一个使用utf8字符集的db2数据库&#x1f4cc;创建一个使用utf8字符集&#xff0c;并带校对规则的db3数据库 二、字符集和校验规则1. 查看系统默认字符集以及校验规则…

Python入门——yield生成器和iter迭代器

yield生成器 yield 的作用 生成器函数&#xff1a;yield 将一个普通的函数变成一个生成器函数。生成器函数与普通函数的区别在于&#xff0c;普通函数使用 return 一次性返回结果并终止&#xff0c;而生成器函数使用 yield 返回一个值后&#xff0c;会记住函数的执行状态&…

铜业机器人剥片 - SNK施努卡

SNK施努卡有色行业电解车间铜业机器人剥片 铜业机器人剥片技术是针对传统人工剥片效率低下、工作环境恶劣及生产质量不稳定的痛点而发展起来的自动化解决方案。 面临人工剥片的诸多挑战&#xff0c;包括低效率、工作环境差、人员流动大以及产品质量控制不精确等问题。 人工剥片…

电机学习-空间矢量合成

一、标量转换理论 设三相标量为 x a , x b , x c x_a,x_b,x_c xa​,xb​,xc​,且满足 x a x b x c 0 x_ax_bx_c 0 xa​xb​xc​0&#xff0c;则有变换&#xff1a; X o u t x a a x b a 2 x c &#xff0c; 其中 a e j 2 3 π , a 2 e − j 2 3 π X_{out}x_aax_ba^2…

深度学习调参大法

目录 trick 1&#xff1a;深度学习调参核心点trick 2&#xff1a;关于 深度学习Model选型问题trick 3&#xff1a;关于数据trick 4&#xff1a;关于调参 4.1 关于 Loss function 调参策略4.2 关于 Learning rate 和 batch size 调参策略4.3 关于 Epoch number 和 early stoppi…

华为ensp静态路由,浮动路由,缺省路由讲解及配置

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;网络通信基础TCP/IP专栏&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年10月24日0点15分 祝大家程序员节快乐~ 路由的选择与管理至关重要。静态路由…

医院信息化与智能化系统(10)

医院信息化与智能化系统(10) 这里只描述对应过程&#xff0c;和可能遇到的问题及解决办法以及对应的参考链接&#xff0c;并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图&#xff0c;可以试试PlantUML&#xff0c;告诉GPT你的文件结构&#xff0c;让他给你对应…

使用 Python 的 BeautifulSoup(bs4)解析复杂 HTML

使用 Python 的 BeautifulSoup&#xff08;bs4&#xff09;解析复杂 HTML&#xff1a;详解与示例 在 Web 开发和数据分析中&#xff0c;解析 HTML 是一个常见的任务&#xff0c;尤其是当你需要从网页中提取数据时。Python 提供了多个库来处理 HTML&#xff0c;其中最受欢迎的就…

ElasticSearch备考 -- index rollover

一、题目 给索引my-index-000001&#xff0c;创建别名my-index&#xff0c;并设置rollover&#xff0c;满足以下三个条件的 The index was created 7 or more days ago.The index contains 5 or more documents.The index’s largest primary shard is 1GB or larger. 二、思考…

nodejs包管理器pnpm

简介 通常在nodejs项目中我们使用npm或者yarn做为默认的包管理器&#xff0c;但是pnpm的出现让我们的包管理器有了更多的选择&#xff0c;pnpm相比npm具有以下优势&#xff1a; 速度更快&#xff0c;pnpm在安装依赖时&#xff0c;会将依赖包缓存到全局目录&#xff0c;下次安…

vue3当中vscode给ref定义的变量使用时自动加上.value

vue3当中vscode给ref定义的变量使用时自动加上.value 1.在扩展中找到vue-office进行安装 2.安装完成后点击设置找到“dot value”勾起即可

Flutter 状态管理框架Get

状态管理框架 Get的使用 目录 状态管理框架 Get的使用 GetMaterialApp 路由的注册 路由的跳转 middlewares的使用 组件使用 defaultDialog bottomSheet snackbar 状态刷新有很多种方式 ValueBuilder Obx 基础使用 是时候引入GetxController, 也是Get里面的常用的 G…

香港国际金融市场的多元化投资策略与风险管理

香港国际金融市场长期以来以其开放性和稳健性闻名&#xff0c;吸引了全球众多投资者。随着全球经济日益互联&#xff0c;投资者在香港市场可以获得多样化的资产选择&#xff0c;包括股票、债券、基金、外汇等多元化金融产品。本文将探讨香港国际金融市场的投资策略和风险管理措…

远程IO控制器ZLAN6808-3 使用JSON定时下发执行DO通断

一.使用场景 对于数据采集控制点是按照线性分布的场景&#xff0c;比如智慧园区的路灯、桥梁、路灯、数字化工厂、停车场车位监测、智慧停车场、智能停车架、楼宇自动控制系统等场景&#xff0c;采用以太网/4G远程I0模块要比采用PLC节省更多的成本。远程IO控制器在很多场景中作…

【无人机设计与控制】基于Astar算法无人机路径规划,优化路径平滑

摘要 本文提出了一种基于A算法的无人机路径规划方法&#xff0c;并通过路径平滑优化提升路径的可行性和安全性。传统A算法在生成路径时&#xff0c;常因路径节点分布不规则导致路径不平滑&#xff0c;影响无人机的飞行效率和安全性。本文通过引入贝塞尔曲线对A*算法生成的路径…

【自动化测试之oracle数据库】MacOs如何安装oracle- client

操作系统为Mac OS&#xff0c;本地在pycharm上跑自动化脚本时&#xff0c;因为有操作oracle数据库的部分&#xff0c;所以需要安装oracle数据库的客户端&#xff0c;并install cx_oracle,本文主要介绍如何在macOS上完成安装&#xff0c;并在python自动化测试代码中配置&#xf…

WPF入门_06资源和样式

目录 1、资源基础介绍 2、静态资源和动态资源区别 3、资源字典 4、共享资源的方法 5、在Custom Control Library中定义和使用共享资源 6、样式 7、样式触发器 1、资源基础介绍 尽管每个元素都提供了Resources属性,但通常在窗口级别上定义资源,如下定义一个字符串资源…

哥德巴赫猜想渐行渐远

我现在的工作&#xff0c;表明经典分析可能出了问题&#xff0c;如此则连Vinogradov的三素数定理都不成立了&#xff0c;更别说基于L-函数方程的陈氏定理“12”了。事实上即使L-函数方程成立&#xff0c;由于我指出Siegel定理不成立&#xff0c;陈景润和张益唐的工作就不成立。…

使用Python和Matplotlib模拟3D海浪动画

使用Python和Matplotlib模拟3D海浪动画 在计算机图形学和动画领域&#xff0c;模拟逼真的海洋表面一直是一个具有挑战性的问题。本文将介绍如何使用Python的Matplotlib库和Gerstner波浪模型&#xff0c;创建一个动态的3D海浪动画。通过叠加多个波浪&#xff0c;我们可以生成复…