【设计模式】【创建型模式】原型模式(Prototype)

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中… 博客更新速度++
👍 欢迎点赞、收藏、关注,跟上我的更新节奏
🎵 当你的天空突然下了大雨,那是我在为你炸乌云

文章目录

  • 一、入门
    • 什么是原型模式?
    • 为什么要有原型模式?
    • 如何实现原型模式?
  • 二、原型模式在框架源码中的使用
    • JDK 的 Object.clone()
    • Java 集合框架中的 ArrayList.clone()
    • Spring Framework 中的 Prototype Bean
  • 三、总结
    • 原型模式的优点
    • 原型模式的缺点
    • 原型模式的适用场景

一、入门

什么是原型模式?

原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有对象来创建新对象,而不是通过实例化类。
原型模式的核心是克隆(Clone),即通过复制现有对象来创建新对象。Java 提供了 Cloneable 接口和 clone() 方法来实现对象的浅拷贝。

为什么要有原型模式?

  1. 对象创建成本高
    • 问题:某些对象的创建过程可能非常复杂,涉及大量的计算或资源消耗。例如,数据库连接、网络请求、复杂的初始化过程等。
    • 解决方案:通过原型模式,可以直接复制现有对象,避免重复进行高成本的初始化过程。
  2. 需要动态配置对象
    • 问题:在某些情况下,对象的配置需要在运行时动态确定,而不是在编译时确定。如果每次都需要重新创建和配置对象,会导致代码复杂且难以维护。
    • 解决方案:原型模式允许通过复制现有对象来创建新对象,并根据需要动态修改其配置。
  3. 避免子类化
    • 问题:在某些情况下,通过继承来扩展对象的功能会导致类层次结构复杂,难以维护。
    • 解决方案:原型模式通过复制现有对象来创建新对象,而不是通过继承来扩展功能,从而简化了类层次结构。
  4. 保持对象状态
    • 问题:在某些情况下,需要创建与现有对象状态相同的新对象。如果每次都手动复制对象的状态,会导致代码冗余且容易出错。
    • 解决方案:原型模式通过克隆现有对象来自动复制其状态,减少了手动复制状态的工作量。

如何实现原型模式?

原型模式由以下角色组成:

  1. 原型接口(Prototype Interface)
    • 定义克隆方法的接口或抽象类。
    • 在 Java 中,通常使用 Cloneable 接口来标记类支持克隆。
  2. 具体原型类(Concrete Prototype)
    • 实现原型接口的具体类,负责实现克隆方法。
    • 通常需要重写 clone() 方法来定义具体的克隆逻辑。
  3. 客户端(Client)
    • 使用原型对象的类,通过调用原型对象的克隆方法来创建新对象。

【案例】打印身份证
在这里插入图片描述
假设你需要复印身份证,每次复印时,原始身份证的内容(姓名、身份证号、地址等)是固定的,但复印件的用途可能不同(如用于银行开户、办理签证等)。如果每次都重新填写身份证信息,效率很低。
原型模式解决方案:

  1. 身份证原件(原型):包含固定的个人信息。
  2. 复印件(克隆对象):复制原件的内容,并根据用途添加额外信息(如用途备注)。

原型接口(Cloneable 是 Java 内置接口): Prototype接口

interface Prototype extends Cloneable {Prototype clone();
}

具体原型类(Concrete Prototype) IDCard

class IDCard implements Prototype {private String name;private String idNumber;private String address;private String purpose; // 复印件的用途public IDCard(String name, String idNumber, String address) {this.name = name;this.idNumber = idNumber;this.address = address;}public void setPurpose(String purpose) {this.purpose = purpose;}@Overridepublic IDCard clone() {try {return (IDCard) super.clone(); // 调用 Object 的 clone() 方法} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}@Overridepublic String toString() {return "IDCard{" +"name='" + name + '\'' +", idNumber='" + idNumber + '\'' +", address='" + address + '\'' +", purpose='" + purpose + '\'' +'}';}
}

客户端

class CopyMachine {public static void main(String[] args) {// 创建身份证原件IDCard originalIDCard = new IDCard("张三", "123456789012345678", "北京市朝阳区");// 复印身份证用于银行开户IDCard copyForBank = originalIDCard.clone();copyForBank.setPurpose("银行开户");// 复印身份证用于办理签证IDCard copyForVisa = originalIDCard.clone();copyForVisa.setPurpose("办理签证");// 打印结果System.out.println("原件: " + originalIDCard);System.out.println("银行开户复印件: " + copyForBank);System.out.println("办理签证复印件: " + copyForVisa);}
}

二、原型模式在框架源码中的使用

JDK 的 Object.clone()

Java 的根类 Object 提供了 clone() 方法,它是原型模式的底层实现基础。任何实现 Cloneable 接口的类都可以通过 clone() 方法创建新对象。

public class Object {protected native Object clone() throws CloneNotSupportedException;
}

使用约束

  • 必须实现 Cloneable 接口:否则调用 clone() 会抛出 CloneNotSupportedException
  • 默认是浅拷贝:需要深拷贝时,必须手动重写 clone() 方法。

Java 集合框架中的 ArrayList.clone()

Java 的 ArrayList 类实现了 Cloneable 接口,其 clone() 方法通过浅拷贝快速复制一个新的列表。

ArrayList<String> original = new ArrayList<>();
original.add("A");
original.add("B");ArrayList<String> copy = (ArrayList<String>) original.clone();
copy.add("C");System.out.println(original); // 输出 [A, B]
System.out.println(copy);     // 输出 [A, B, C]
源码实现
public class ArrayList<E> implements Cloneable {// ...public Object clone() {try {ArrayList<?> v = (ArrayList<?>) super.clone();v.elementData = Arrays.copyOf(elementData, size);v.modCount = 0;return v;} catch (CloneNotSupportedException e) {throw new InternalError(e);}}
}

Spring Framework 中的 Prototype Bean

Spring 框架中的 Bean 作用域(Scope)之一是 prototype,它表示每次从容器中获取 Bean 时都会创建一个新的实例。这本质上是原型模式的一种应用。

<!-- XML 配置 -->
<bean id="prototypeBean" class="com.example.PrototypeBean" scope="prototype"/>
// Java 代码中获取 Bean
ApplicationContext context = ...;
PrototypeBean bean1 = context.getBean(PrototypeBean.class);
PrototypeBean bean2 = context.getBean(PrototypeBean.class);// bean1 和 bean2 是两个不同的实例
System.out.println(bean1 == bean2); // 输出 false

设计思想

  • 核心机制:Spring 容器内部维护一个原型 Bean 的模板,每次调用 getBean() 时,基于模板创建一个新对象(通过反射或 CGLIB 动态代理)。
  • 优势:避免单例 Bean 的线程安全问题,适用于需要独立状态的场景(如 HTTP 请求处理)。

三、总结

原型模式的优点

  1. 高效创建对象
    • 通过复制现有对象来创建新对象,避免了重复的初始化过程,特别适用于创建成本较高的对象(如数据库连接、复杂计算对象)。
    • 例如,Spring 的 Prototype Bean 每次请求都会创建一个新实例,避免了单例 Bean 的线程安全问题。
  2. 动态配置对象
    • 可以在运行时动态修改克隆对象的属性,而不需要重新初始化。
    • 例如,复制一个配置对象后,可以根据需要调整某些参数。
  3. 减少子类化
    • 通过复制现有对象来创建新对象,而不是通过继承来扩展功能,避免了类层次结构的复杂性。
    • 例如,JavaScript 中的原型继承就是通过复制原型对象来实现的。
  4. 标准化对象创建
    • 提供统一的克隆接口(如 Cloneable),使得对象创建过程更加标准化和可控。

原型模式的缺点

  1. 深拷贝与浅拷贝问题
    • 默认的 clone() 方法是浅拷贝,如果对象包含引用类型字段,克隆对象和原对象会共享这些字段,可能导致意外的副作用。
    • 实现深拷贝需要额外的工作(如手动复制引用类型字段或使用序列化工具)。
  2. 实现复杂度
    • 如果对象结构非常复杂(如包含嵌套对象、循环引用等),实现深拷贝可能会变得复杂且容易出错。
  3. 破坏封装性
    • clone() 方法是 Object 类的受保护方法,需要在子类中重写并公开,这可能破坏类的封装性。
  4. 性能问题
    • 深拷贝(如基于序列化的拷贝)可能比较耗时,特别是在对象结构复杂或数据量大的情况下。

原型模式的适用场景

  1. 对象创建成本高
    • 当对象的创建过程涉及复杂的计算、资源消耗(如数据库连接、网络请求)或耗时操作时,使用原型模式可以显著提高性能。
    • 例如,Spring 的 Prototype Bean 适用于需要独立状态的场景。
  2. 需要动态配置对象
    • 当对象的配置需要在运行时动态确定时,可以通过克隆现有对象并修改其属性来实现。
    • 例如,复制一个配置模板并根据环境调整参数。
  3. 避免子类化
    • 当需要通过扩展对象的功能来创建新对象,但又不想引入复杂的类层次结构时,可以使用原型模式。
    • 例如,JavaScript 中的原型继承。
  4. 需要保持对象状态一致性
    • 当需要创建与现有对象状态相同的新对象时,可以通过克隆来确保状态一致性。
    • 例如,游戏中的敌人生成、缓存对象的复制。
  5. 框架中的对象管理
    • 在框架中,原型模式常用于管理对象的生命周期和创建过程(如 Spring 的 Prototype Bean、Java 集合框架的 clone() 方法)。

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

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

相关文章

Weblogic 反序列化漏洞深度剖析与复现

目录 一、引言 二、Weblogic 反序列化漏洞原理 &#xff08;一&#xff09;什么是反序列化 &#xff08;二&#xff09;Weblogic 反序列化漏洞产生机制 三、Weblogic 反序列化漏洞危害 四、Weblogic 反序列化漏洞复现 &#xff08;一&#xff09;复现环境准备 &#xff…

2025年02月19日Github流行趋势

项目名称&#xff1a;OmniParser 项目地址url&#xff1a;https://github.com/microsoft/OmniParser 项目语言&#xff1a;Jupyter Notebook 历史star数&#xff1a;12878 今日star数&#xff1a;2153 项目维护者&#xff1a;yadong-lu, ThomasDh-C, aliencaocao, nmstoker, kr…

深入解析 iOS 视频录制(三):完整录制流程的实现与整合

深入解析 iOS 视频录制&#xff08;一&#xff09;&#xff1a;录制管理核心MWRecordingController 类的设计与实现 深入解析iOS视频录制&#xff08;二&#xff09;&#xff1a;自定义UI的实现​​​​​​​ 深入解析 iOS 视频录制&#xff08;三&#xff09;&#xff1a;完…

基于豆瓣2025电影数据可视化分析系统的设计与实现

✔️本项目旨在通过对豆瓣电影数据进行综合分析与可视化展示&#xff0c;构建一个基于Python的大数据可视化系统。通过数据爬取收集、清洗、分析豆瓣电影数据&#xff0c;我们提供了一个全面的电影信息平台&#xff0c;为用户提供深入了解电影产业趋势、影片评价与演员表现的工…

tcp协议连接,和传输数据

1、连接 这个是通用的 2、传送数据 当连接建立后&#xff0c;客户端和服务器都可以主动发送数据&#xff0c;分别如下 1》客户端先发送数据 这里是单向的&#xff0c;服务器没有对客户端的数据内容进行应答&#xff0c;只是单纯的对报文应答ack 2》服务器先发送数据

2024年国赛高教杯数学建模C题农作物的种植策略解题全过程文档及程序

2024年国赛高教杯数学建模 C题 农作物的种植策略 原题再现 根据乡村的实际情况&#xff0c;充分利用有限的耕地资源&#xff0c;因地制宜&#xff0c;发展有机种植产业&#xff0c;对乡村经济的可持续发展具有重要的现实意义。选择适宜的农作物&#xff0c;优化种植策略&…

鸿蒙开发:V2版本装饰器之@Monitor装饰器

前言 本文代码案例基于Api13。 随着官方的迭代&#xff0c;在新的Api中&#xff0c;对于新的应用开发&#xff0c;官方已经建议直接使用V2所属的装饰器进行开发了&#xff0c;所以&#xff0c;能上手V2的尽量上手V2吧&#xff0c;毕竟&#xff0c;V2是V1的增强版本&#xff0c;…

国产编辑器EverEdit - 独门暗器:自动监视剪贴板内容

1 监视剪贴板 1.1 应用场景 如果需要对剪贴板的所有历史进行记录&#xff0c;并进行分析和回顾&#xff0c;则可以使用监视剪贴板功能&#xff0c;不仅在EverEdit中的复制会记录&#xff0c;在其他应用的复制也会记录。 1.2 使用方法 新建一个空文档(重要&#xff1a;防止扰乱…

pdf转换成word在线 简单好用 支持批量转换 效率高 100%还原

pdf转换成word在线 简单好用 支持批量转换 效率高 100%还原 在数字化办公的浪潮中&#xff0c;文档格式转换常常让人头疼不已&#xff0c;尤其是 PDF 转 Word 的需求极为常见。PDF 格式虽然方便阅读和传输&#xff0c;但难以编辑&#xff0c;而 Word 格式却能灵活地进行内容修…

深入探索C语言中的字符串处理函数:strstr与strtok

在C语言的字符串处理领域&#xff0c; strstr 和 strtok 是两个非常重要的函数&#xff0c;它们各自承担着独特的功能&#xff0c;为开发者处理字符串提供了强大的支持。 一、strstr函数&#xff1a;字符串查找的利器 strstr 函数用于在一个字符串中查找另一个字符串的首次出现…

AIGC(生成式AI)试用 21 -- Python调用deepseek API

1. 安装openai pip3 install openai########################## Collecting openaiUsing cached openai-1.61.1-py3-none-any.whl.metadata (27 kB) Collecting anyio<5,>3.5.0 (from openai)Using cached anyio-4.8.0-py3-none-any.whl.metadata (4.6 kB) Collecting d…

关于使用雪花算法生成唯一ID,返回给前端ID不一致的问题

问题 在某个项目中,使用雪花算法生成的唯一ID,从数据库查询到数据后返回给前端,但是前端接受到的数据ID和数据库原先生成的不一致 但是前端展示的数据: 原因 原因是后端使用Long类型来存储雪花算法生成的ID,但是这个数值已经超过前端数值类型的范围,导致前端在存储这个数值…

Windows 启动 SSH 服务

Windows 启动 SSH 服务 一、OpenSSH Server 安装 以 Win10 系统为例 打开设置 -> 系统 -> 可选功能 在 添加的功能 查看是否安装了 OpenSSH 服务 或者 OpenSSH Server 如果没有安装&#xff0c;找到 系统->添加可选功能 -> 查看功能->搜索 OpenSSH 服务 ->…

C#功能测试

List 内部元素为引用 src[0]为"11" List<Source> src new List<Source>(); src.Add(new Source() { Name "1", Age 1, Description "1" }); src.Add(new Source() { Name "2", Age 2, Description "2"…

大数据SQL调优专题——Flink执行原理

引入 上一篇我们了解了Spark&#xff0c;相比起MapReduce来说&#xff0c;它确实已经快了超级多了&#xff0c;但是人类的欲望是没有止境的&#xff0c;这也是推动人类进步的动力。 Flink就是为了满足实时响应的场景需求诞生的。 其实在Flink之前&#xff0c;实时处理其实已…

计算机视觉:神经网络实战之手势识别(附代码)

第一章&#xff1a;计算机视觉中图像的基础认知 第二章&#xff1a;计算机视觉&#xff1a;卷积神经网络(CNN)基本概念(一) 第三章&#xff1a;计算机视觉&#xff1a;卷积神经网络(CNN)基本概念(二) 第四章&#xff1a;搭建一个经典的LeNet5神经网络(附代码) 第五章&#xff1…

win11安装wsl报错:无法解析服务器的名称或地址(启用wsl2)

1. 启用wsl报错如下 # 查看可安装的 wsl --install wsl --list --online此原因是因为没有开启DNS的原因&#xff0c;所以需要我们手动开启DNS。 2. 按照如下配置即可 Google的DNS&#xff08;8.8.8.8和8.8.4.4) 全国通用DNS地址 (114.114.114.114) 3. 运行以下命令来重启 WSL…

开源模型应用落地-DeepSeek-R1-Distill-Qwen-7B-LoRA微调-LLaMA-Factory-单机单卡-V100(一)

一、前言 如今&#xff0c;大语言模型领域热闹非凡&#xff0c;各种模型不断涌现。DeepSeek-R1-Distill-Qwen-7B 模型凭借其出色的效果和性能&#xff0c;吸引了众多开发者的目光。而 LLaMa-Factory 作为强大的微调工具&#xff0c;能让模型更好地满足个性化需求。 在本篇中&am…

k8s-对接NFS存储

一、前提条件 1、NFS_Server 部署好了。 2、网络可达。 二、 使用方式 1、CSI **项目地址 https://github.com/kubernetes-csi/csi-driver-nfs#readme Install NFS CSI driver v4.10.0 version on a kubernetes cluster If you have already installed Helm, you can a…

【动态路由】系统Web URL资源整合系列(后端技术实现)【nodejs实现】

需求说明 软件功能需求&#xff1a;反向代理功能&#xff08;描述&#xff1a;apollo、eureka控、apisix、sentinel、普米、kibana、timetask、grafana、hbase、skywalking-ui、pinpoint、cmak界面、kafka-map、nacos、gateway、elasticsearch、 oa-portal 业务应用等多个web资…