设计模式(五)创建型:原型模式详解

原型模式(Prototype Pattern)是 GoF 23 种设计模式中的创建型模式之一,其核心价值在于通过复制现有对象来创建新对象,而不是通过 new 关键字调用构造函数。它特别适用于对象创建成本高、构造复杂或运行时动态决定类型扩展的场景。原型模式通过克隆机制规避了昂贵的初始化过程,提升了性能,并支持在不依赖具体类的情况下动态生成对象,是实现对象复用与运行时灵活性的重要手段。在配置管理、游戏开发、文档模板系统、对象池等场景中具有广泛应用。

一、原型模式详细介绍

原型模式解决的是“对象创建效率”与“运行时灵活性”的问题。当一个对象的创建过程涉及复杂的数据加载、资源分配或计算逻辑时,频繁使用构造函数会导致性能瓶颈。原型模式通过“克隆”一个已存在的实例(即“原型”)来快速生成新对象,避免重复执行初始化逻辑。

该模式涉及以下核心角色:

  • Prototype(原型接口):声明一个克隆(clone)方法,用于返回当前对象的副本。通常在 Java 中通过实现 Cloneable 接口并重写 Object.clone() 方法实现。
  • ConcretePrototype(具体原型类):实现 Prototype 接口,提供具体的克隆逻辑。它定义了如何复制自身的状态。
  • Client(客户端):持有对 Prototype 的引用,通过调用 clone() 方法而非构造函数来创建新对象。

原型模式的关键在于克隆的深度

  • 浅克隆(Shallow Clone):仅复制对象本身及其基本类型字段,对于引用类型字段,只复制引用地址,不复制被引用的对象。Java 默认的 Object.clone() 实现即为浅克隆。
  • 深克隆(Deep Clone):不仅复制对象本身,还递归复制其所有引用对象,确保新对象与原对象完全独立,互不影响。

选择浅克隆还是深克隆取决于业务需求:若对象包含共享状态或大型资源(如缓存、连接池),浅克隆可节省内存;若要求对象完全独立,则需深克隆。

与“工厂模式”相比,原型模式不依赖类的构造逻辑,而是基于现有实例进行复制,因此更适合运行时动态配置对象的场景。例如,系统启动时加载一个“默认配置”对象作为原型,后续所有新配置均基于此原型克隆并修改,避免重复解析配置文件。

二、原型模式的UML表示

以下是原型模式的标准 UML 类图:

implements
implements
contains
«interface»
Prototype
+clone()
ConcretePrototypeA
-field1: String
-field2: int
-reference: Component
+clone()
ConcretePrototypeB
-data: List<String>
+clone()
Component
-name: String

图解说明

  • Prototype 接口定义 clone() 方法,返回一个 Prototype 类型的对象。
  • ConcretePrototypeAConcretePrototypeB 是具体实现类,各自实现 clone() 方法。
  • ConcretePrototypeA 包含一个 Component 类型的引用字段,克隆时需决定是浅复制还是深复制该引用。
  • 客户端通过调用 prototype.clone() 获取新对象,无需知道其具体类名,实现了创建过程的解耦。

三、一个简单的Java程序实例

以下是一个基于原型模式的 Java 示例,模拟配置对象的克隆过程:

import java.util.ArrayList;
import java.util.List;// 组件类:被引用的对象
class ServerConfig {private String host;private int port;public ServerConfig(String host, int port) {this.host = host;this.port = port;}// 提供复制构造函数用于深克隆public ServerConfig copy() {return new ServerConfig(this.host, this.port);}// Getter and Setterpublic String getHost() { return host; }public void setHost(String host) { this.host = host; }public int getPort() { return port; }public void setPort(int port) { this.port = port; }@Overridepublic String toString() {return "ServerConfig{" +"host='" + host + '\'' +", port=" + port +'}';}
}// 抽象原型接口
interface Configuration extends Cloneable {Configuration clone();
}// 具体原型类:应用配置
class AppConfiguration implements Configuration {private String appName;private int timeout;private boolean debugMode;private ServerConfig primaryServer;           // 引用类型private List<String> allowedOrigins;          // 集合类型// 构造函数:用于创建初始原型public AppConfiguration(String appName, int timeout, boolean debugMode,ServerConfig primaryServer, List<String> allowedOrigins) {this.appName = appName;this.timeout = timeout;this.debugMode = debugMode;this.primaryServer = primaryServer;this.allowedOrigins = new ArrayList<>(allowedOrigins); // 防止外部修改}// 深克隆实现@Overridepublic Configuration clone() {try {// 先调用 Object.clone() 进行浅克隆AppConfiguration cloned = (AppConfiguration) super.clone();// 对引用类型字段进行深克隆cloned.primaryServer = this.primaryServer.copy(); // 使用复制构造函数cloned.allowedOrigins = new ArrayList<>(this.allowedOrigins); // 复制集合内容return cloned;} catch (CloneNotSupportedException e) {throw new RuntimeException("Clone failed", e);}}// Getter and Setter 方法(省略部分)public String getAppName() { return appName; }public void setAppName(String appName) { this.appName = appName; }public int getTimeout() { return timeout; }public void setTimeout(int timeout) { this.timeout = timeout; }public boolean isDebugMode() { return debugMode; }public void setDebugMode(boolean debugMode) { this.debugMode = debugMode; }public ServerConfig getPrimaryServer() { return primaryServer; }public void setPrimaryServer(ServerConfig primaryServer) { this.primaryServer = primaryServer; }public List<String> getAllowedOrigins() { return new ArrayList<>(allowedOrigins); }@Overridepublic String toString() {return "AppConfiguration{" +"appName='" + appName + '\'' +", timeout=" + timeout +", debugMode=" + debugMode +", primaryServer=" + primaryServer +", allowedOrigins=" + allowedOrigins +'}';}
}// 客户端使用示例
public class PrototypePatternDemo {public static void main(String[] args) {// 创建一个“默认配置”原型对象ServerConfig defaultServer = new ServerConfig("localhost", 8080);List<String> defaultOrigins = List.of("https://example.com", "https://api.example.com");AppConfiguration defaultConfig = new AppConfiguration("MyApp",30,false,defaultServer,defaultOrigins);System.out.println("=== 原始原型 ===");System.out.println(defaultConfig);// 克隆原型并修改部分配置,用于开发环境AppConfiguration devConfig = (AppConfiguration) defaultConfig.clone();devConfig.setAppName("MyApp-Dev");devConfig.setTimeout(60);devConfig.setDebugMode(true);devConfig.getPrimaryServer().setHost("dev-server.local");devConfig.getAllowedOrigins().add("http://localhost:3000");System.out.println("\n=== 开发环境配置(克隆后修改)===");System.out.println(devConfig);// 验证原始对象未被影响(深克隆效果)System.out.println("\n=== 原始原型是否被修改?===");System.out.println(defaultConfig);// 输出显示 defaultConfig 的 primaryServer 仍为 localhost,allowedOrigins 无 localhost:3000}
}

运行说明

  • defaultConfig 作为原型对象,可能通过复杂过程(如读取配置文件、数据库查询)创建。
  • devConfig 通过 clone() 方法创建,避免重复初始化。
  • clone() 中实现了深克隆,确保 devConfig 修改 primaryServerallowedOrigins 不影响 defaultConfig
  • 客户端无需知道 AppConfiguration 的构造细节,只需调用 clone() 即可获得新实例。

四、总结

原型模式通过对象克隆机制,实现了以下关键优势:

  • 提升性能:避免重复执行昂贵的初始化逻辑,尤其适合大型或复杂对象。
  • 简化对象创建:无需了解构造参数,只需复制已有实例。
  • 支持运行时动态性:可在运行时基于用户配置或环境动态生成对象。
  • 实现对象解耦:客户端不依赖具体类,仅通过接口调用 clone()

但也存在缺点:

  • 克隆逻辑复杂:深克隆需手动处理所有引用字段,易出错。
  • 内存开销:每个克隆对象都占用独立内存,浅克隆可能引发意外共享。
  • 不适用于所有场景:若对象状态频繁变化或包含临时资源(如连接),克隆可能导致不一致。

因此,应在“创建成本”与“内存/维护成本”之间权衡使用。

架构师洞见:
原型模式是“对象复用”与“运行时灵活性”的典范。在现代架构中,其思想已融入配置中心(如 Spring Cloud Config)、对象池(如数据库连接池预热)、游戏实体生成、A/B 测试配置分发等场景。架构师应认识到:原型模式的本质是将“对象模板”与“实例化过程”分离,实现“一次构建,多次复用”。未来,随着云原生和 Serverless 架构的发展,函数冷启动问题使得“预初始化实例池 + 克隆分发”成为优化启动延迟的有效策略。此外,结合序列化(JSON/XML/Binary)实现跨进程或跨服务的原型传递,将进一步拓展其应用边界。掌握原型模式,有助于设计出高性能、低延迟、高弹性的系统,是应对高并发与动态配置挑战的重要工具。

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

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

相关文章

K8S 八 数据存储-高级存储PV PVC 生命周期;配置存储ConfigMap Secret

目录数据存储 Volume8.1 基本存储8.1.1 EmptyDir8.1.2 HostPath 挂载目录8.1.3 NFSnfs的服务8.2 高级存储8.2.1 PV和PVC8.2.2 PV 持久化卷申请8.2.3 PVC 资源申请PVC的配置参数8.2.4 生命周期配置存储8.3.1 ConfigMap8.3.2 Secret数据存储 Volume Kubernetes的Volume支持多种类…

Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现轮船检测识别(C#代码UI界面版)

Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现轮船检测识别&#xff08;C#代码UI界面版&#xff09;工业相机使用YoloV8模型实现轮船检测识别工业相机通过YoloV8模型实现轮船检测识别的技术背景在相机SDK中获取图像转换图像的代码分析工业相机图像转换Bitmap图像格…

自习室预约小程序的设计与实现

自习室预约小程序的设计与实现现代学习环境对高效、便捷的预约系统需求日益增长。自习室预约小程序结合前沿技术栈&#xff0c;提供流畅的用户体验和强大的后台管理功能&#xff0c;满足学生、职场人士等群体的自习需求。技术架构与核心功能Vue.js 构建动态前端界面 采用 Vue.j…

Docker 实战大纲

文章目录Docker 实战 – Mysql &#xff08;敬请期待……&#xff09;

从一个“诡异“的C++程序理解状态机、防抖与系统交互

引言 在编程世界中&#xff0c;有时一个看似简单的代码片段可能隐藏着令人惊讶的复杂性。本文将从一个"故意设计"的C程序出发&#xff0c;深入探讨其背后涉及的状态机模式、防抖机制以及操作系统与控制台的交互原理。通过这个案例&#xff0c;我们不仅能理解这些核心…

NAS-Bench-101: Towards Reproducible Neural Architecture Search

概述这篇题为"NAS-Bench-101: Towards Reproducible Neural Architecture Search"的论文由Chris Ying等人合作完成&#xff0c;旨在解决神经网络架构搜索(NAS)领域面临的重大挑战&#xff1a;计算资源需求高和实验难以复现的问题。论文提出了NAS-Bench-101&#xff0…

SpringBoot整合Fastexcel/EasyExcel导出Excel导出多个图片

整个工具的代码都在Gitee或者Github地址内 gitee&#xff1a;solomon-parent: 这个项目主要是总结了工作上遇到的问题以及学习一些框架用于整合例如:rabbitMq、reids、Mqtt、S3协议的文件服务器、mongodb、xxl-job、powerjob还有用Docker compose部署各类中间组件。如果大家有…

网络原理--HTTPHTTPS

目录 一、HTTP 1.1 HTTP是什么 1.2 HTTP协议的工作过程 1.3 HTTP协议格式 1.3.1 抓包工具的使用 1.3.2 抓包结果 1.4 HTTP请求 1.4.1 URL 1.4.2 认识“方法” (method) 1.4.3 认识请求“报头”(header) 1.4.4 认识请求“正文”(body) 1.5 HTTP 响应详解 1.5.1 HTTP…

『 C++ 入门到放弃 』- 哈希表

一、哈希的概念 哈希&#xff0c;也称「 散列 」是一种用来进行高效查找的数据结构&#xff0c;查找的时间复杂度平均为O(1)&#xff0c;其本质就是依赖哈希函数这个算法来将 key 和该 key 存储位置建立一个映射关系。 而因为是有着映射关系&#xff0c;所以哈希的事件复杂度为…

零售收银系统开源代码全解析:连锁门店一体化解决方案(含POS+进销存+商城)

过去10年&#xff0c;收银系统技术经历了从单机版到云服务、从单纯结算到全渠道整合的快速演进。面对连锁多门店、AI称重、智能分账、跨店库存同步等新需求&#xff0c;很多企业的现有传统saas系统已显乏力。本文将梳理收银系统关键技术指标&#xff0c;助您在系统升级时做出明…

能源高效利用如何实现?楼宇自控系统智能化监管建筑设备

随着全球能源危机日益严峻和“双碳”目标的持续推进&#xff0c;建筑领域作为能耗大户&#xff08;约占社会总能耗的40%&#xff09;&#xff0c;其节能潜力备受关注。楼宇自控系统&#xff08;Building Automation System&#xff0c;简称BAS&#xff09;作为建筑智能化的核心…

校园二手交易小程序的设计与实现

文章目录前言详细视频演示具体实现截图后端框架SpringBoot微信小程序持久层框架MyBaits成功系统案例&#xff1a;参考代码数据库源码获取前言 博主介绍:CSDN特邀作者、985高校计算机专业毕业、现任某互联网大厂高级全栈开发工程师、Gitee/掘金/华为云/阿里云/GitHub等平台持续…

Redis(二):Redis高级特性和应用(慢查询、Pipeline、事务)

Redis的慢查询 许多存储系统&#xff08;例如 MySQL)提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间&#xff0c;当超过预设阀值,就将这条命令的相关信息&#xff08;例如:发生时间&#xff0c;耗时&…

如何为你的WordPress网站选择合适的安全插件

在管理WordPress网站时&#xff0c;安全因素至关重要。由于WordPress的广泛使用&#xff0c;它也成为了黑客攻击的首要目标。为了避免潜在的安全风险&#xff0c;选择合适的安全插件至关重要。而Wordfence和iThemes&#xff0c;作为两款颇具人气的WordPress安全插件&#xff0c…

我们使用Rust开发的AI知识库应用

这段时间陆陆续续的开发了2个AI知识库应用&#xff0c;一个面向企业&#xff0c;一个面向C端用户。 飞树智库&#xff1a;一个安全高效的面向 企业的知识库平台&#xff08;https://fskb.coderbox.cn/&#xff09;。 小飞树&#xff1a;一个专注于个人知识管理的AI应用&#…

自动化测试实战篇

目录 1. 自动化实施步骤 1.1 编写web测试用例 1.2 自动化测试脚本开发 1.3 将自动化测试补充至测试报告 1. 自动化实施步骤 1.1 编写web测试用例 1.2 自动化测试脚本开发 TestDevelopment: 测试用例 - Gitee.comhttps://gitee.com/Axurea/test-development/tree/master/2…

idea 服务器Debug端口启动设置

一&#xff1a;在阿里云服务器安全组已经设置了端口授权对象&#xff1a;正确命令&#xff1a;nohup java -Xdebug -Xrunjdwp:transportdt_socket,servery,suspendn,address9998 -jar -Duser.timezoneGMT08 -Xms256m -Xmx256m /opt/projects/*/*/*-starter-1.0-SNAPSHOT.jar -…

大模型量化004

Bert P-tuning BertPET、BertP-Tuning Chain of Thought Few shot Cot Auto-COT 解决手动编写高质量CoT示例麻烦耗时的问题 Auto COT 自动思维链生成器 1.业务场景&#xff1a; 每天收到很多反馈&#xff0c;之前需要人工整理&#xff0c;找到重点&#xff0c;做判断那些需要立…

C#(基本语法)

数据类型C#是一种强类型语言&#xff0c;变量必须声明类型。基本数据类型包括整型&#xff08;int、long&#xff09;、浮点型&#xff08;float、double&#xff09;、布尔型&#xff08;bool&#xff09;、字符型&#xff08;char&#xff09;和字符串型&#xff08;string&a…

ARM-I2C软实现

开发流程引脚初始化引脚功能定义实现读操作实现写操作GD32F4软件I2C初始化void SoftI2C_init() {// 时钟配置rcu_periph_clock_enable(SCL_RCU);// 设置输出模式gpio_mode_set(SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SCL_PIN);gpio_output_options_set(SCL_PORT, GPIO_O…