设计模式——原型设计模式(创建型)

article/2025/6/19 6:00:22

摘要

本文详细介绍了原型设计模式,这是一种创建型设计模式,通过复制现有对象(原型)来创建新对象,避免使用new关键字,可提高性能并简化对象创建逻辑。文章阐述了其优点,如提高性能、动态扩展和简化构造逻辑,以及缺点,如深拷贝实现复杂、复杂资源复制困难和易破坏封装性。还介绍了使用条件、结构、实现方式、适合场景和实战示例,并探讨了Spring中原型思想的应用。

1. 原型设计模式定义

原型设计模式是一种创建型设计模式,其核心思想是:通过复制现有的对象(原型)来创建新对象,而不是通过 new 关键字来实例化,从而提高性能并简化对象创建逻辑。使用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。

特性

说明

创建方式

使用已有对象(原型)复制创建,而不是 new

拷贝类型

通常支持 浅拷贝深拷贝

接口

通常实现 Cloneable接口,重写 clone()方法(Java)

性能

适合对象创建代价高、结构复杂的场景

1.1. ✅ 原型模式的优点

  1. 提高性能:避免重复创建复杂对象。
  2. 动态扩展:在运行时动态创建对象。
  3. 简化构造逻辑:不用关心构造细节,只需拷贝。

1.2. ❌ 缺点

  • 深拷贝实现复杂(需注意引用对象)
  • 对象包含复杂资源(如数据库连接)时不易复制
  • 克隆过程容易破坏封装性

1.3. 📌 原型设计模式使用条件

适合以下场景:

场景

说明

对象构造开销大

如数据库连接、网络通信等初始化代价高

对象构造逻辑复杂

包含多个参数、状态配置等

多个相似对象

只需要改变少部分属性

2. 原型设计模式结构

2.1. 原型设计模式类图

  1. 客户(Client)角色:客户类提出创建对象的请求。
  2. 抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。
  3. 具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口

2.2. 原型设计模式时序图

3. 原型设计模式实现方式

原型设计模式的实现方式核心在于 —— 通过克隆现有对象来创建新对象,而不是使用 new。在 Java 中,通常通过实现 Cloneable 接口并重写 clone() 方法来完成。下面是常见的两种实现方式:浅拷贝和深拷贝。

3.1. 🛠️ 原型模式实现方式

实现方式

描述

浅拷贝

复制对象本身,但对象中的引用类型字段只复制地址(共享引用)

深拷贝

复制对象及其引用对象(创建完全独立的新对象)

3.2. ✅ 浅拷贝示例(实现 Cloneable)

@Data
public class Person implements Cloneable {private String name;private int age;@Overridepublic Person clone() {try {return (Person) super.clone(); // 浅拷贝} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}
}

✅ 浅拷贝适用于字段都是基本类型或不可变类型(如 String)。

3.3. ✅ 深拷贝示例(引用字段也复制)

@Data
public class Person implements Cloneable {private String name;private int age;private Address address; // 引用类型@Overridepublic Person clone() {try {Person cloned = (Person) super.clone();// 深拷贝 Address 对象cloned.address = address.clone();return cloned;} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}
}@Data
class Address implements Cloneable {private String city;@Overridepublic Address clone() {try {return (Address) super.clone();} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}
}

3.4. 🔁 使用序列化实现深拷贝(通用方案)

public static <T extends Serializable> T deepCopy(T obj) {try (ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos)) {oos.writeObject(obj);try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis)) {return (T) ois.readObject();}} catch (Exception e) {throw new RuntimeException("深拷贝失败", e);}
}

3.5. 📌 实现步骤总结

步骤

描述

1. 实现 Cloneable接口

否则调用 clone()会抛异常

2. 重写 clone()方法

调用 super.clone()并处理引用类型字段

3. 深拷贝时递归调用子对象的 clone()

保证对象间完全独立

3.6. 💡 Tips(在项目中使用时注意):

  • 不要忘了处理 引用类型字段(深拷贝)
  • 可以用工具类如 Apache Commons Lang 的 SerializationUtils.clone() 简化处理
  • Java record 类型天然不可变,结合原型模式更安全
  • Spring 中 @Scope("prototype") 是原型思想的一种应用

4. 原型设计模式适合场景

原型设计模式(Prototype Pattern)适用于通过复制(克隆)现有对象来快速创建新对象的场景。以下是它适用和不适用的场景对比:

4.1. ✅ 适合使用原型模式的场景

场景

说明

对象创建成本高

构造函数复杂、耗时(如 I/O、数据库、复杂计算)时,通过克隆避免重复创建

对象初始化复杂

需要设置很多配置/参数,克隆一个已初始化好的对象更方便

需要大量相似对象

如游戏中怪物/兵种生成、工作流中节点复制、表单复制等

运行时动态创建对象

不依赖类名和构造函数,只要能访问 prototype 对象即可

避免工厂或 new 创建的耦合

提高系统灵活性,符合开闭原则

4.2. ❌ 不适合使用原型模式的场景

场景

原因

对象结构简单、创建成本低

使用 new即可,没必要增加 clone 成本

对象包含复杂的循环引用关系

clone 实现困难,容易出错

频繁深拷贝,性能反而变差

clone 比 new 还慢,得不偿失

对象包含外部不可复制资源

如线程、Socket、数据库连接等资源不能复制

需要严格控制对象创建流程

比如工厂方法模式更适合定制构造逻辑

4.3. 🧠 实际项目应用建议

建议

说明

复杂对象或批量对象创建场景优先考虑

如任务调度系统中复制任务模板

引用类型多的对象必须小心实现深拷贝

避免共享引用带来的副作用

尽量配合原型注册表(原型缓存池)

管理所有 prototype 模板,集中创建

5. 原型设计模式实战示例

在 Spring 项目中,原型设计模式(Prototype Pattern)最典型的应用方式是使用 Spring 的 @Scope("prototype") 注解来声明一个 Bean 为原型模式,使得每次注入都会创建一个新实例。

5.1. ✅ 示例:批量生成任务模板对象(适合原型模式场景)

5.1.1. 定义一个任务对象(复杂初始化逻辑)

@Data
public class Task implements Cloneable {private String name;private String type;private List<String> steps = new ArrayList<>();public Task(String name, String type) {this.name = name;this.type = type;this.steps.add("初始化");this.steps.add("执行中");this.steps.add("结束");}@Overridepublic Task clone() {try {Task clone = (Task) super.clone();// 深拷贝clone.steps = new ArrayList<>(this.steps);return clone;} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}
}

5.1.2. Spring容器中定义该对象为原型 Bean

@Configuration
public class TaskConfig {@Bean@Scope("prototype") // 每次注入时都会创建新实例public Task taskPrototype() {return new Task("默认任务", "general");}
}

5.1.3. 任务服务中使用 Prototype Bean并进行克隆

@Service
public class TaskService {@Autowiredprivate ApplicationContext applicationContext;public Task createNewTask(String name, String type) {// 每次从容器获取都会是一个新实例(原型)Task prototype = applicationContext.getBean(Task.class);Task newTask = prototype.clone(); // 克隆一份再设置参数newTask.setName(name);newTask.setType(type);return newTask;}
}

5.1.4. ✅ 为什么这是原型模式适合的场景?

说明

创建成本高

每个任务初始化流程复杂,创建频繁

需要批量创建不同配置的对象

每个任务有不同参数,复用模板快速创建

运行时动态变化

原型对象提供灵活性,可随时根据当前需求构造

6. 原型设计模式思考

6.1. Spring 中 @Scope("prototype") 是原型思想的一种应用?

使用 @Scope("prototype") 标注的 Bean,每次从 Spring 容器中获取时,都会创建一个全新的实例,而不是复用同一个对象。这就是“原型”的核心思想。

Prototype 模式的定义:“用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。”(即:通过复制一个“原型对象”来生成新对象

6.1.1. Spring 中如何实现这个思想?

Prototype 模式要素

Spring 的对应机制

原型对象

Bean 的定义(类 + 配置)

拷贝新对象

每次调用 getBean(),Spring 通过反射“创建新对象”

统一管理原型

由 Spring 容器负责构造、注入依赖等生命周期管理

6.1.2. 示例

@Component
@Scope("prototype")
public class Task {public Task() {System.out.println("新任务实例被创建");}
}
@Autowired
private ApplicationContext applicationContext;public void createTasks() {Task t1 = applicationContext.getBean(Task.class); // 创建一个新实例Task t2 = applicationContext.getBean(Task.class); // 再创建一个新实例System.out.println(t1 == t2); // false
}

6.1.3. prototype与singleton 的区别

特性

singleton(默认)

prototype

实例个数

全局一个

每次请求新建

生命周期管理

Spring 管

Spring 只负责创建,不管理销毁

适用场景

共享服务、无状态组件

有状态对象、频繁创建的临时对象

博文参考

  • 创建型 - 原型模式(Prototype) | Java 全栈知识体系
  • 原型设计模式

http://www.hkcw.cn/article/BlUJXdoNYO.shtml

相关文章

java程序从服务器端到Lambda函数的迁移与优化

source&#xff1a;https://www.jfokus.se/jfokus24-preso/From-Serverful-to-Serverless-Java.pdf 从传统的服务器端Java应用&#xff0c;到如今的无服务器架构。这不仅仅是技术名词的改变&#xff0c;更是开发模式和运维理念的一次深刻变革。先快速回顾一下我们熟悉的“服务…

57、IdentityServer4概述

IdentityServer4是一个基于ASP.NET Core的开源身份认证和授权框架&#xff0c;实现了OpenID Connect和OAuth 2.0协议。它为现代应用程序提供集中式的身份验证和授权服务&#xff0c;支持单点登录&#xff08;SSO&#xff09;、令牌颁发与验证、会话管理等功能&#xff0c;广泛应…

2025.5.29 学习日记 docker概念以及基本指令

Docker&#xff1a; Docker 是一种开源的容器化平台&#xff0c;用于快速部署应用程序&#xff0c;实现开发、测试和生产环境的一致性。 一、Docker 核心概念 镜像&#xff08;Image&#xff09; 只读的模板文件&#xff0c;用于创建容器&#xff0c;类似虚拟机的镜像&#x…

AI与智能驾驶的关系和原理:技术融合与未来展望-优雅草卓伊凡一、AI大模型基础原理与智能驾驶

AI与智能驾驶的关系和原理&#xff1a;技术融合与未来展望-优雅草卓伊凡 一、AI大模型基础原理与智能驾驶 1.1 AI大模型的核心架构 本内容由优雅草木心为卓伊凡提供技术辅助讲解&#xff0c;毕竟木心目前正在比亚迪。 人工智能大模型是基于深度学习的复杂神经网络系统&#…

企业AI部署热潮下的安全隐忧:速度与安全的博弈

数据来源&#xff1a;企业网D1net 企业AI部署热潮下的安全隐忧&#xff1a;速度与安全的博弈 近年来&#xff0c;生成式人工智能&#xff08;GenAI&#xff09;的迅猛发展让企业趋之若鹜。然而&#xff0c;在这场技术竞赛中&#xff0c;不少企业却因盲目追求速度而忽视了安全…

分析XSSstrike源码

#用于学习web安全自动化工具# 我能收获什么&#xff1f; 1.XSS漏洞检测机制 学习如何构造和发送XSS payload如何识别响应中的回显&#xff0c;WAF&#xff0c;过滤规则等如何使用词典&#xff0c;编码策略&#xff0c;上下文探测等绕过过滤器 2.Python安全工具开发技巧 使…

通过mqtt 点灯

1 解析mqtt 传过来的json 用cjson 解析。 2 类似mvc的结构&#xff0c;调用具体的动作函数 定义设备处理结构体&#xff1a;使用结构体数组映射设备名称与处理函数&#xff0c;实现可扩展的指令分发分离设备逻辑&#xff1a;为每个设备&#xff08;如 LED、Motor&#xff0…

解锁技术世界的“秘密知识库”:The Book of Secret Knowledge 深度解析

在浩如烟海的技术文档中,你是否渴望一个集中式宝库,收录那些资深工程师口耳相传的“秘密武器”?GitHub 上爆火的 The Book of Secret Knowledge 正是这样一个令人惊叹的集合。今天我们来深入探索这个项目,挖掘它的核心价值。 🔍 项目核心:不是什么,而是什么 不是一本传…

M4Pro安装ELK(ElasticSearch+LogStash+Kibana)踩坑记录

ElasticSearch安装&#xff0c;启动端口9200&#xff1a; docker pull elasticsearch:8.13.0 新增配置文件elasticsearch.yml&#xff1a; cd /opt/homebrew/etc/ mkdir elasticsearch_config cd elasticsearch_config vi elasticsearch.yml cluster.name: "nfturbo…

VC++: identifer “M_PI“ is undefined

本周拿到一份算法文件&#xff08;cpp),尝试在本机跑一下&#xff0c;提示M_PI不识别&#xff1a; identifer "M_PI" is undefined 解决方案&#xff1a; #define _USE_MATH_DEFINES

关于镜像如何装进虚拟机

本篇文章为感谢小仙猪老师特别编写 本篇文章仅以Ubuntu为例 目录 创建虚拟机 汉化 如果没有China选项 检查网络 创建虚拟机 第一步&#xff0c;创建虚拟机 因为&#xff0c;第一个选项是会把虚拟机的文件放在c盘因此&#xff0c;这里博主选择自定义&#xff0c;然后下一…

青柠日记:记录美好,守护隐私

在快节奏的现代生活中&#xff0c;日记成为了许多人记录生活、抒发情感的重要方式。而青柠日记这款软件&#xff0c;以其便捷的操作、丰富的模板和强大的隐私保护功能&#xff0c;为用户提供了一个理想的日记记录平台。无论是日常的琐碎点滴&#xff0c;还是重要的生活事件&…

【技能拾遗】——家庭宽带单线复用布线与配置(移动2025版)

&#x1f4d6; 前言&#xff1a;在家庭网络拓扑中&#xff0c;客厅到弱电箱只预埋了一根网线&#xff0c;由于已将广电的有线电视取消并改用IPTV。现在需要解决在客厅布置路由器和观看IPTV问题&#xff0c;这里就用到单线复用技术。 目录 &#x1f552; 1. 拓扑规划&#x1f55…

Visual Studio笔记:MSVC工具集、MSBuild

1. MSVC工具集 1.1 什么叫MSVC工具集 也可以说Visual Studio平台工具集&#xff08;Platform toolset&#xff09;. 这些工具包括 C/C 编译器、链接器、汇编程序和其他生成工具以及匹配的库和头文件。 Visual Studio 2015、Visual Studio 2017 和 Visual Studio 2019 是二进制…

【系统配置与部署类】docker的深度配置和应用

相关文章已经在个人博客网站上更新&#xff0c;欢迎访问&#xff1a; docker的深度配置和应用http://www.turnin-blog.online/articles/%E7%B3%BB%E7%BB%9F%E9%85%8D%E7%BD%AE%E4%B8%8E%E9%83%A8%E7%BD%B2/docker%E7%9A%84%E6%B7%B1%E5%BA%A6%E9%85%8D%E7%BD%AE%E5%92%8C%E5%B…

Redis最佳实践——安全与稳定性保障之数据持久化详解

Redis 在电商应用的安全与稳定性保障之数据持久化全面详解 一、持久化机制深度解析 1. 持久化策略矩阵 策略触发方式数据完整性恢复速度适用场景RDB定时快照分钟级快容灾备份/快速恢复AOF实时追加日志秒级慢金融交易/订单关键操作混合模式RDBAOF同时启用秒级中等高安全要求场…

告别硬编码!用工厂模式优雅构建可扩展的 Spring Boot 应用 [特殊字符]

嗨&#xff0c;各位技术伙伴们&#xff01;&#x1f44b; 在日常的软件开发中&#xff0c;我们经常面临需求变更的挑战。如何构建一个既能满足当前需求&#xff0c;又能轻松应对未来变化的系统呢&#xff1f;答案往往藏在那些经典的设计模式中。 今天&#xff0c;我们就来聊聊…

azure web app创建分步指南系列之二

为注册表授权托管标识 你创建的托管标识尚未获得从容器注册表中提取数据的授权。在此步骤中,你将启用授权。 返回容器注册表的管理页面: 在左侧导航菜单中,选择“访问控制 (IAM)”。选择“添加角色分配”。此屏幕截图显示了如何为容器注册表启用添加角色分配。在角色列表中…

使用Yolov8 训练交通标志数据集:TT100K数据集划分

使用Yolov8 训练交通标志数据集&#xff1a;TT100K数据集划分&#xff08;一&#xff09; 一、数据集下载二、划分数据集三、目录放置 一、数据集下载 官方网址&#xff1a;TT100K 数据集对比 源码如下&#xff1a; def classes(filedir):with open(filedir) as f:classes …

【PostgreSQL 03】PostGIS空间数据深度实战:从地图服务到智慧城市

PostGIS空间数据深度实战&#xff1a;从地图服务到智慧城市 关键词 PostGIS, 空间数据库, 地理信息系统, GIS, 空间查询, 地理分析, 位置服务, 智慧城市, 空间索引, 坐标系统 摘要 PostGIS是PostgreSQL的空间数据扩展&#xff0c;它将普通的关系数据库转变为强大的地理信息系统…