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

🎯 设计模式专栏,持续更新中, 欢迎订阅: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. 深拷贝
    • 复制对象的所有属性,包括递归复制引用类型对象
    • 拷贝后的对象和原始对象完全独立,互不影响。
    • 修改其中一个对象的引用类型内容,不会影响另一个对象。

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

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

相关文章

Linux查看服务器日志

一、tail 这个是我最常用的一种查看方式 用法如下: tail -n 10 test.log 查询日志尾部最后10行的日志; tail -n 10 test.log 查询10行之后的所有日志; tail -fn 10 test.log 循环实时查看最后1000行记录(最常用的)一般还会配合着grep用&#xff…

视频监控平台中的视频处理核心技术揭秘:自动化监控与智能预警成为趋势?

随着科技的飞速发展,视频监控作为安全管理与信息获取的重要手段,其技术也在不断革新与优化。一个高效的视频监控平台,不仅依赖于先进的硬件设备,更离不开强大的视频处理技术作为支撑。在众多视频监控平台中,安防监控Ea…

Linux 文件与目录权限管理指南

文章目录 Linux 文件与目录权限管理指南文件与目录权限的基本概念常用权限管理命令ls -l:查看文件权限chmod:修改文件权限符号模式数字模式 chown:更改文件所有者和所属组chgrp:只更改文件所属组umask:设置默认权限 示…

Autosar(Davinci) --- 创建一个S/R类型的port(下)

前言: 前面章节我们讲解了S/R类型的Port如何创建,这一章节,我们着重讲一下生成的代码,以及我们如何添加代码让这些门与灯之间的关系产生连接。 一、CtSaDoor.c 在【Rte.c】的【IO_TASK】中我们可以看到,反复的判断Rte_Ev_Cyclic_IO_Task_0_200ms这个条件是否成立,当200…

RabbitMQ创建交换机和队列——配置类 注解

交换机的类型 Fanout:广播,将消息交给所有绑定到交换机的队列。 Direct:订阅,基于RoutingKey(路由key)发送给订阅了消息的队列。 Topic:通配符订阅,与Direct类似,只不…

python如何获取html中的所有链接

在Python中,获取HTML页面中的所有链接通常可以通过使用第三方库如BeautifulSoup或lxml来完成。这里,我将提供一个使用BeautifulSoup库的示例,因为它简单易用且功能强大。 首先,你需要安装BeautifulSoup和requests库(如…

数据分析-前期数据处理

今天找到一份关于医学体检的数据,在数据分析前期工作需要对数据做处理,在这里我们对原始数据做一些处理,将数据处理为可分析的标准数据。下一篇文章做数据的分析。数据想要获取的话可以到我的资源下载。1 数据读取 import pandas as pd data…

Vue3 父组件向子组件传值:异步数据处理的显示问题

一、问题场景 假设我们有一个父组件和一个子组件,父组件需要经过一些复杂的计算或者异步操作才能得到要传递给子组件的值。在数据还没有准备好的时候,子组件尝试获取并显示这个值,这就可能导致子组件没有数据可显示或者显示了一个不正确的初…

中国农业银行——数据湖建设

【金融机构开源技术应用创新成果案例 第十五期】 中国农业银行——数据湖建设 技术领域:大数据 技术产品:Hudi、Alluxio、Flink、Atlas、Monaco Editor、AntvX6 业务场景:实时经营管理、实时运维管理、数据运营管理、数据开发 应用时间:2021年12月 一、案例背景 十三…

rust + bevy 实现小游戏 打包成wasm放在浏览器环境运行

游戏界面 代码地址 github WASM运行 rustup target install wasm32-unknown-unknown cargo install wasm-server-runner cargo run --target wasm32-unknown-unknowncargo install wasm-bindgen-cli cargo build --release --target wasm32-unknown-unknown wasm-bindgen --…

SpringBoot动态SQL

目录 动态SQL【重点】 1、 SQL片段 2、if 3、where [重点] 4、 set 5、 foreach 动态SQL【重点】 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘…

python的循环结构

引言 在前面的课程中,我们已经学习了 Python 的基本输入输出、数据类型及其转换、顺序结构和分支结构。本课时将介绍 Python 中的循环结构,主要讨论如何使用 for 循环和 while 循环来重复执行一段代码。通过一个具体的示例——打印九九乘法表&#xff0c…

开源 TTS 模型「Fish Speech」1.4 发布;GameGen-O :生成开放世界游戏视频模型丨 RTE 开发者日报

开发者朋友们大家好: 这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。 我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、…

yarn webpack脚手架 react+ts搭建项目

安装 Yarn 首先,确保你已经安装了 Node.js 和 Yarn。如果还没有安装 Yarn,可以通过以下命令安装: npm install -g yarn创建项目 使用 create-react-app 脚手架创建一个带有 TypeScript 的项目,node更新到最新版,并指定…

Unity Apple Vision Pro 开发(十):通过图像识别锚定空间

XR 开发者社区链接: SpatialXR社区:完整课程、项目下载、项目孵化宣发、答疑、投融资、专属圈子 课程试看:https://www.bilibili.com/video/BV1mpH9eVErW 课程完整版,答疑仅社区成员可见,可以通过文章开头的链接加入…

产品探秘|开物——面向AI原生和云原生网络研究的首选科研平台

在当今高速发展的信息技术领域,特别是对于那些致力于前沿科技探索与实践的高校而言,拥有一款能够支持复杂网络业务研究与开发的平台至关重要。开物™数据网络开发平台(Data Network Development Platform,简称DNDP)&am…

Go协程及并发锁应用指南

概念 协程(Goroutine)是Go语言独有的并发体,是一种轻量级的线程,也被称为用户态线程。相对于传统的多线程编程,协程的优点在于更加轻量级,占用系统资源更少,切换上下文的速度更快,不…

ClickHouse的安装配置+DBeaver远程连接

1、clickhouse的下载: 先去clickhouse官网进行下载,继续往下翻找文档,将DBeaver也下载下来 下载地址:https://packages.clickhouse.com/rpm/stable/ 下载这个四个rpm包 2、上传rmp文件到Linux中 自己创建的一个clickhouse-ins…

ceph简介

ceph存储简要概述: 通过将文件分解成固定大小对象,然后存放于pool中,每个pool中 可包含多个pg,每个pg中又可包含多个osd 通过crush算法 最终数据落盘到osd中去。 一、ceph 删除osd 步骤1 修改osd数据操作权重值 ceph osd crush r…

【人工智能】MOE架构的详细解析

🏆🏆欢迎大家来到我们的天空🏆🏆 🏆🏆如果文章内容对您有所触动,别忘了点赞、关注,收藏! 🏆 作者简介:我们的天空 🏆《头衔》&#x…