当前位置: 首页 > news >正文

原型模式详细介绍和代码实现

🎯 设计模式专栏,持续更新中, 欢迎订阅:JAVA实现设计模式
🛠️ 希望小伙伴们一键三连,有问题私信都会回复,或者在评论区直接发言

Java实现原型模式

介绍: 原型模式(Prototype Pattern)是一种创建型设计模式,允许通过复制已有对象来创建新对象,而不需要依赖其具体类。这种模式的关键在于克隆现有对象,而不是通过直接实例化新对象,从而避免重复的复杂对象构建过程。

🎯 案例场景:

假设我们在开发一个游戏角色系统,每个角色都有不同的属性,比如力量、敏捷和智力。创建一个新角色需要耗费大量的计算资源(如生成外貌、装备等)。如果我们想要快速创建一个与现有角色相似的新角色,只需要在原有角色基础上进行微调,而不重新生成所有属性。

我们可以使用原型模式,通过复制已有角色对象,再对其进行调整,来生成新的角色。

原型模式的核心步骤:

  1. Prototype 接口:定义 clone() 方法,所有需要被复制的对象实现该接口。
  2. 具体原型类:实现 clone() 方法,用于创建对象的副本。
  3. 客户端代码:通过调用 clone() 方法来复制已有对象。

🧑‍💻 Java代码实现:

在这里插入图片描述

import java.util.HashMap;
import java.util.Map;// 1. 定义原型接口 Prototype
interface GameCharacter extends Cloneable {GameCharacter clone();void display();
}// 2. 具体的角色类实现原型接口
class Warrior implements GameCharacter {private String name;private int strength;private int agility;private int intelligence;public Warrior(String name, int strength, int agility, int intelligence) {this.name = name;this.strength = strength;this.agility = agility;this.intelligence = intelligence;}// 实现 clone 方法@Overridepublic Warrior clone() {try {return (Warrior) super.clone();  // 调用 Object 类的 clone 方法} catch (CloneNotSupportedException e) {throw new RuntimeException("Clone not supported", e);}}// 展示角色信息@Overridepublic void display() {System.out.println("Warrior [Name: " + name + ", Strength: " + strength +", Agility: " + agility + ", Intelligence: " + intelligence + "]");}
}// 3. 客户端代码,使用原型模式
public class PrototypePatternDemo {public static void main(String[] args) {// 创建一个原始的角色Warrior originalWarrior = new Warrior("Arthas", 80, 50, 30);originalWarrior.display();// 使用克隆方法复制角色Warrior clonedWarrior = originalWarrior.clone();// 修改克隆对象的某些属性clonedWarrior.display();// 现在,原始角色和克隆角色的内存地址不同,但属性相同System.out.println("Original Warrior HashCode: " + originalWarrior.hashCode());System.out.println("Cloned Warrior HashCode: " + clonedWarrior.hashCode());}
}

📋 解释:

  1. GameCharacter 接口:定义了 clone() 方法,表示所有实现这个接口的类都可以被克隆。
  2. Warrior:实现了 GameCharacter 接口,并通过 super.clone() 进行浅克隆。这个方法通过复制对象的当前状态来创建一个新实例。
  3. 客户端代码:首先创建了一个 Warrior 对象 originalWarrior,并使用其 clone() 方法创建了一个副本 clonedWarrior。然后可以自由修改克隆对象的属性,而不影响原始对象。

🌟 应用场景:

  1. 对象创建开销大,不希望每次都通过构造函数创建。
  2. 需要保存对象的初始状态,以便在不同地方进行修改和操作。
  3. 游戏开发中,需要频繁创建相似但稍有不同的角色或物品。

深拷贝和浅拷贝

浅拷贝:复制对象时,只复制对象的基本属性引用类型的引用。即如果对象的属性是引用类型(如数组、对象),浅拷贝只会复制这些引用,而不是引用所指向的实际对象。因此,拷贝后的对象和原始对象共享这些引用类型的数据,修改引用类型的内容会影响原始对象。

深拷贝:不仅会复制对象的基本属性,还会递归地复制引用类型所指向的对象,即引用对象也会完全复制成一个新的副本。这样,拷贝后的对象与原始对象完全独立,修改拷贝对象的引用类型内容,不会影响原始对象。

🌟 案例解释:

假设我们有一个 Person 类,里面包含基本类型属性 name 和引用类型 address

1. 浅拷贝示例:

浅拷贝只复制基本属性和引用对象的引用,不复制引用对象本身。

class Address {String city;public Address(String city) {this.city = city;}
}class Person implements Cloneable {String name;Address address;public Person(String name, Address address) {this.name = name;this.address = address;}// 浅拷贝@Overridepublic Person clone() {try {return (Person) super.clone();  // 调用 Object 的 clone 方法} catch (CloneNotSupportedException e) {throw new RuntimeException("Clone not supported", e);}}public void display() {System.out.println("Name: " + name + ", City: " + address.city);}
}public class ShallowCopyDemo {public static void main(String[] args) {Address address = new Address("New York");Person person1 = new Person("John", address);Person person2 = person1.clone();  // 浅拷贝// 显示原始和克隆对象person1.display();  // Name: John, City: New Yorkperson2.display();  // Name: John, City: New York// 修改克隆对象的 addressperson2.address.city = "San Francisco";// 浅拷贝后,原始对象的 address 也被改变person1.display();  // Name: John, City: San Franciscoperson2.display();  // Name: John, City: San Francisco}
}

结果解释

  • person2person1 的浅拷贝。
  • person2address.city 修改为 "San Francisco" 后,person1address.city 也变成了 "San Francisco"。这是因为浅拷贝只复制了引用,两个对象共享同一个 Address 对象。
2. 深拷贝示例:

深拷贝需要复制所有对象,包括引用对象中的数据。

class Address implements Cloneable {String city;public Address(String city) {this.city = city;}@Overridepublic Address clone() {try {return (Address) super.clone();  // 克隆 Address 对象} catch (CloneNotSupportedException e) {throw new RuntimeException("Clone not supported", e);}}
}class Person implements Cloneable {String name;Address address;public Person(String name, Address address) {this.name = name;this.address = address;}// 深拷贝@Overridepublic Person clone() {try {Person clonedPerson = (Person) super.clone();clonedPerson.address = address.clone();  // 深拷贝 Addressreturn clonedPerson;} catch (CloneNotSupportedException e) {throw new RuntimeException("Clone not supported", e);}}public void display() {System.out.println("Name: " + name + ", City: " + address.city);}
}public class DeepCopyDemo {public static void main(String[] args) {Address address = new Address("New York");Person person1 = new Person("John", address);Person person2 = person1.clone();  // 深拷贝// 显示原始和克隆对象person1.display();  // Name: John, City: New Yorkperson2.display();  // Name: John, City: New York// 修改克隆对象的 addressperson2.address.city = "San Francisco";// 深拷贝后,原始对象的 address 未被改变person1.display();  // Name: John, City: New Yorkperson2.display();  // Name: John, City: San Francisco}
}

结果解释

  • person2person1 的深拷贝。
  • person2address.city 修改为 "San Francisco" 后,person1address.city 仍然是 "New York"。这是因为深拷贝创建了 Address 对象的独立副本,两个对象不再共享同一个引用。

🔍 关键区别总结:

  1. 浅拷贝
    • 只复制对象的基本类型属性引用的地址,不复制引用的实际内容。
    • 拷贝后的对象与原对象共享引用类型的对象。
    • 如果修改了引用类型的数据,原始对象也会受到影响。
  2. 深拷贝
    • 复制对象的所有属性,包括递归复制引用类型对象
    • 拷贝后的对象和原始对象完全独立,互不影响。
    • 修改其中一个对象的引用类型内容,不会影响另一个对象。

相关文章:

原型模式详细介绍和代码实现

🎯 设计模式专栏,持续更新中, 欢迎订阅:JAVA实现设计模式 🛠️ 希望小伙伴们一键三连,有问题私信都会回复,或者在评论区直接发言 Java实现原型模式 介绍: 原型模式(Prototype Patte…...

ArcGIS Pro SDK (十三)地图创作 5 图层样式

ArcGIS Pro SDK (十三)地图创作 5 图层样式 文章目录 ArcGIS Pro SDK (十三)地图创作 5 图层样式1 风格管理1.1 如何按名称获取项目中的样式1.2 如何创建新样式1.3 如何向项目添加样式1.4 如何从项目中删除样式1.5 如何将样式项添加到样式1.6 如何从样式中删除样式项1.7 如…...

【Python报错已解决】 Requests.exceptions.ProxyError: HTTPSConnectionPool

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 专栏介绍 在软件开发和日常使用中,BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…...

现在量化中普遍使用QMT和PTrade?哪家可以同时提供QMT/PTrade?

QMT的特点 全面的功能集成: QMT集成了行情显示、策略研究、交易执行和风控管理于一体,为投资者提供了一站式的量化交易解决方案。 高效的交易执行能力: 通过全内存交易实现低延迟的交易执行,单笔延时小于1ms,确保了交易…...

【计算机网络】UDP 协议详解及其网络编程应用

文章目录 一、引言二、UDP1、UDP的协议格式2、UDP 报文的解包和分用3、UDP面向数据报的特点 三、UDP输入输出四、UDP网络编程 一、引言 UDP(User Datagram Protocol,用户数据报协议)是一种网络通信协议,它属于传输层的协议。是一…...

基于ESP32S3的链接大语言模型对话模块

本实物模块从实物外观、模块组成、API申请及功能说明四部分来介绍这款基于ESP32S3的大语言模型对话模块。 1、实物外观 2、模块介绍 本硬件平台主要由三个模块组成,包括MAX9814录音模块、MAX98357音频功放模块和ESP32S3模块。如下图所示。 MAX9814录音模块&#…...

Cpp输出多字符常量警告

Cpp输出多字符常量警告 Cpp中用单引号(single quotes)表示单个字符(single character),例如a,$,用双引号(double quotes)表示字符串文本(text),例如"Hello World! " 当在一个单引号里面存在多个字符时,Cpp…...

Maven从入门到精通(二)

一、什么是pom.xml pom.xml是Maven项目的核心配置文件,它是 项目对象模型 - Project Object Model(POM)的缩写。POM定义了项目的所有属性,包括项目的名称、版本、依赖关系、构建配置等。使用pom.xml,我们可以轻松地管…...

【Kubernetes】常见面试题汇总(二十四)

目录 71.假设一家公司想要修改它的部署方法,并希望建立一个更具可扩展性和响应性的平台。您如何看待这家公司能够实现这一目标以满足客户需求? 72.考虑一家拥有非常分散的系统的跨国公司,期待解决整体代码库问题。您认为公司如何解决他们的问…...

最低成本的游戏串流方案分享 如何自己打造云电脑?

今天教大家如何最低成本实现串流 出门在外也可以随时随地游玩端游大作 硬件准备:一台电脑 手机/平板一台 软件:Gameviewer远程 为啥不用moonlight等其他软件呢 因为设置公网穿透等复杂操作对小白来说不太友好 而GameViewer从安装到使用仅需一键 对比同类…...

python运行时错误:找不到fbgemm.dll

python运行时错误:找不到fbgemm.dll 报错: OSError: [WinError 126] 找不到指定的模块。 Error loading "D:\program\py\312\Lib\site-packages\torch\lib\fbgemm.dll" or one of its dependencies. 原因是Windows下缺失:libomp140…...

给虚拟机linux系统安装交叉编译工具链

我们在电脑上写的代码编译生成的是X86架构的二进制文件,只能在X86平台上运行,而开发板是ARM架构因此需要安装交叉编译链工具,这样在电脑上写的代码交叉编译之后生成的是ARM架构的二进制文件。 绿色的字眼是与本文无关的只是这样有助于我们的…...

Redhat 7,8系(复刻系列) 一键部署Oracle21c-xe rpm

Oracle21c-xe前言 无论您是开发人员、DBA、数据科学家、教育工作者,还是仅仅对数据库感兴趣,Oracle Database Express Edition (XE) 都是理想的入门方式。它是全球企业可依赖的强大的 Oracle Database,提供简单的下载、易于使用和功能齐全的体验。您可以在任何环境中使用该…...

Web植物管理系统-下位机部分

本节主要展示上位机部分,采用BSP编程,不附带BSP中各个头文件的说明,仅仅是对main逻辑进行解释 main.c 上下位机通信 通过串口通信,有两位数据验证头(verify数组中保存对应的数据头 0xAA55) 通信格式 上位发送11字节…...

leetcode169. 多数元素

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入:nums [3,2,3] 输出:3 示例…...

从大脑图谱/ROI中提取BOLD信号

动机 在功能连接(Functional Connectivity,FC)构建过程中,由于FC中元素数目是节点数目的平方关系,所以在计算FC之前进行数据降维是一个常见的选择。 一般会将体素级/顶点级BOLD信号(在2mm的图像分辨率下大脑…...

Java-数据结构-优先级队列(堆)-(一) (;´д`)ゞ

文本目录: ❄️一、优先级队列: ➷ 1、概念: ❄️二、优先级队列的模拟实现: ➷ 1、堆的概念: ➷ 2、堆的性质: ➷ 3、堆的创建: ▶ 向下调整: ➷ 4、堆的插入和删除: …...

工厂模式(二):工厂方法模式

一、概念 工厂方法模式(Factory Method),定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。从而使得系统更加灵活。客户端可以通过调用工厂方法来创建所需的产品,而不必…...

【洛谷】P11036 【MX-X3-T3】「RiOI-4」GCD 与 LCM 问题 的题解

【洛谷】P11036 【MX-X3-T3】「RiOI-4」GCD 与 LCM 问题 的题解 题目传送门 题解 神奇构造题qaq 简化一下下题目,就是要求 a b c d gcd ⁡ ( a , b ) lcm ⁡ ( c , d ) a b c d \gcd(a, b) \operatorname{lcm}(c,d) abcdgcd(a,b)lcm(c,d) 分类讨论 …...

MyBatis系统学习(三)——动态SQL

MyBatis 是一款优秀的持久层框架,它通过 XML 或注解方式将 SQL 语句与 Java 对象映射起来。动态 SQL 是 MyBatis 中非常强大的功能之一,能够根据不同的条件动态生成 SQL 语句。动态 SQL 通过各种标签来灵活生成 SQL,从而避免了在代码中拼接 S…...

7.4.分块查找

一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

Android15默认授权浮窗权限

我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...

Monorepo架构: Nx Cloud 扩展能力与缓存加速

借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...

网页端 js 读取发票里的二维码信息(图片和PDF格式)

起因 为了实现在报销流程中,发票不能重用的限制,发票上传后,希望能读出发票号,并记录发票号已用,下次不再可用于报销。 基于上面的需求,研究了OCR 的方式和读PDF的方式,实际是可行的&#xff…...