原型模式详解与实践

在软件开发的奇妙世界里,我们常常面临重复创建相似对象的任务。如果每次创建都要从头开始设置各种属性和状态,不仅繁琐,还可能降低效率。原型模式就像一位神奇的魔法师,为我们提供了一种通过复制现有对象来创建新对象的优雅方式。它不仅能提高对象创建的效率,还能简化代码结构,让我们在开发过程中更加得心应手。本文将深入探讨原型模式的奥秘,带您领略其在实际应用中的魅力。

一、原型模式的定义与概念

原型模式是一种创建型设计模式,其核心思想是通过复制(克隆)现有对象来创建新对象,而不是通过传统的实例化方式。在原型模式中,有一个原型对象,它定义了用于创建克隆对象的接口(通常是一个克隆方法)。其他对象可以通过调用这个克隆方法,创建出与原型对象具有相同属性和状态的新对象。

想象一下,您正在开发一款游戏,游戏中有许多具有相似属性的角色,如士兵。每个士兵都有相同的基本装备、初始生命值等属性。如果使用传统的对象创建方式,每次创建新士兵都需要重复设置这些属性。而借助原型模式,您只需创建一个 “原型士兵”,然后通过克隆这个原型,就能快速创建出大量具有相同初始状态的新士兵,大大提高了开发效率。

二、原型模式的结构与实现

2.1 结构

原型模式主要涉及以下几个角色:

  • 抽象原型(Prototype):定义克隆方法的接口,所有需要被克隆的具体类都必须实现这个接口。
  • 具体原型(ConcretePrototype):实现抽象原型接口,重写克隆方法,在克隆方法中返回自身的一个副本。
  • 客户端(Client):使用原型对象的克隆方法来创建新对象。

2.2 实现示例

// 抽象原型
interface Prototype {Prototype clone();
}// 具体原型
class ConcretePrototype implements Prototype {private String data;public ConcretePrototype(String data) {this.data = data;}@Overridepublic Prototype clone() {// 这里可以使用浅拷贝或深拷贝,此处为浅拷贝示例return new ConcretePrototype(data);}public void setData(String data) {this.data = data;}public String getData() {return data;}
}// 客户端
public class Client {public static void main(String[] args) {ConcretePrototype prototype = new ConcretePrototype("初始数据");ConcretePrototype clone = (ConcretePrototype) prototype.clone();System.out.println("原型对象数据: " + prototype.getData());System.out.println("克隆对象数据: " + clone.getData());clone.setData("修改后的数据");System.out.println("修改后克隆对象数据: " + clone.getData());System.out.println("原型对象数据: " + prototype.getData());}
}

在上述示例中,ConcretePrototype 类实现了 Prototype 接口的 clone 方法,通过创建一个新的 ConcretePrototype 对象并传入相同的数据来实现克隆。客户端代码中,先创建了一个原型对象 prototype,然后通过调用 clone 方法得到克隆对象 clone。可以看到,克隆对象与原型对象在初始时数据相同,但修改克隆对象的数据并不会影响原型对象。

三、浅拷贝与深拷贝

在实现原型模式的克隆方法时,需要考虑浅拷贝和深拷贝的问题。

  • 浅拷贝:浅拷贝会创建一个新对象,该对象的基本数据类型属性与原对象相同,而引用类型属性则与原对象共享相同的内存地址。也就是说,浅拷贝只复制对象的表面层次,不会递归复制对象内部的引用对象。在上述示例中,使用的就是浅拷贝方式。如果 ConcretePrototype 类中有一个引用类型的属性,如 List<String>,当对原型对象进行浅拷贝后,克隆对象和原型对象的这个 List 属性会指向同一个内存地址,修改其中一个对象的 List 内容会影响到另一个对象。
  • 深拷贝:深拷贝不仅会复制对象的基本数据类型属性,还会递归地复制对象内部的所有引用类型属性,创建出一个完全独立的副本。实现深拷贝通常需要更复杂的操作,例如使用序列化和反序列化的方式来复制对象及其所有内部引用对象。以下是一个简单的深拷贝示例(假设 ConcretePrototype 类中只有一个 List<String> 类型的属性):
import java.io.*;
import java.util.ArrayList;
import java.util.List;// 抽象原型
interface Prototype {Prototype clone();
}// 具体原型
class ConcretePrototype implements Prototype, Serializable {private List<String> dataList;public ConcretePrototype(List<String> dataList) {this.dataList = new ArrayList<>(dataList);}@Overridepublic Prototype clone() {try {ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(this);ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);return (ConcretePrototype) ois.readObject();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();return null;}}public void addData(String data) {dataList.add(data);}public List<String> getDataList() {return dataList;}
}// 客户端
public class Client {public static void main(String[] args) {List<String> originalList = new ArrayList<>();originalList.add("元素1");ConcretePrototype prototype = new ConcretePrototype(originalList);ConcretePrototype clone = (ConcretePrototype) prototype.clone();System.out.println("原型对象数据列表: " + prototype.getDataList());System.out.println("克隆对象数据列表: " + clone.getDataList());clone.addData("元素2");System.out.println("修改后克隆对象数据列表: " + clone.getDataList());System.out.println("原型对象数据列表: " + prototype.getDataList());}
}

在这个深拷贝示例中,ConcretePrototype 类实现了 Serializable 接口,通过将对象序列化到字节数组,再从字节数组反序列化来创建一个完全独立的克隆对象。这样,克隆对象和原型对象的 dataList 属性相互独立,修改一个对象的 dataList 不会影响另一个对象。

四、原型模式的应用场景

4.1 对象创建成本较高

当创建一个对象需要进行复杂的初始化操作、读取大量数据或执行耗时的计算时,使用原型模式通过克隆现有对象可以显著提高效率。例如,在地理信息系统(GIS)中,创建一个包含详细地图数据的地图对象可能需要从数据库中读取大量的地理数据,并进行复杂的渲染初始化。如果需要创建多个相似的地图对象,使用原型模式克隆已有的地图对象可以避免重复的读取和初始化操作,提高系统响应速度。

4.2 大量相似对象的创建

在游戏开发、模拟系统等场景中,经常需要创建大量具有相似属性的对象。如前文提到的游戏中的士兵角色,或者模拟城市中的建筑物、车辆等。通过原型模式,可以快速创建这些相似对象,减少开发工作量和内存开销。

4.3 动态创建对象

在一些需要根据运行时条件动态创建对象的场景中,原型模式非常有用。例如,在一个图形绘制软件中,用户可以通过复制已有的图形元素来创建新的元素,并根据需要进行修改。这种情况下,使用原型模式可以方便地实现对象的动态创建和个性化定制。

五、原型模式的优缺点

5.1 优点

  • 提高创建效率:避免了重复的初始化操作,对于创建成本较高的对象,通过克隆可以快速得到新对象,提高系统性能。
  • 简化对象创建过程:无需像传统方式那样每次都设置对象的所有属性,只需克隆原型对象并按需修改部分属性即可。
  • 增强扩展性:当需要创建新的对象类型时,只需创建一个新的具体原型类并实现克隆方法,无需修改大量的客户端代码。

5.2 缺点

  • 深拷贝实现复杂:如果需要实现深拷贝,特别是对象结构复杂时,实现过程会比较繁琐,可能涉及到递归复制和序列化等操作,增加了代码的复杂性和维护成本。
  • 克隆对象可能存在风险:如果克隆对象的过程中出现错误,可能会导致克隆出的对象状态不正确,影响系统的正常运行。而且,对于一些包含资源(如文件句柄、网络连接等)的对象,克隆可能会导致资源管理问题,需要特别小心处理。

 

结语 

感谢您的阅读!如果您对原型模式或其他设计模式有更多问题或见解,欢迎继续探讨。希望这篇文章能够为您的编程之旅带来启发和帮助。  

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

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

相关文章

【Rust自学】11.1. 编写和运行测试

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 11.1.1. 什么是测试 在Rust里一个测试就是一个函数&#xff0c;它被用于验证非测试代码的功能是否和预期一致。 在一个测试的函数体里通…

数据分析思维(八):分析方法——RFM分析方法

数据分析并非只是简单的数据分析工具三板斧——Excel、SQL、Python&#xff0c;更重要的是数据分析思维。没有数据分析思维和业务知识&#xff0c;就算拿到一堆数据&#xff0c;也不知道如何下手。 推荐书本《数据分析思维——分析方法和业务知识》&#xff0c;本文内容就是提取…

57. Three.js案例-创建一个带有聚光灯和旋转立方体的3D场景

57. Three.js案例-创建一个带有聚光灯和旋转立方体的3D场景 实现效果 该案例实现了使用Three.js创建一个带有聚光灯和旋转立方体的3D场景。 知识点 WebGLRenderer&#xff08;WebGL渲染器&#xff09; THREE.WebGLRenderer 是 Three.js 中用于将场景渲染为 WebGL 内容的核…

Idea-离线安装SonarLint插件地址

地址&#xff1a; SonarQube for IDE - IntelliJ IDEs Plugin | Marketplace 选择Install Plugin from Disk..&#xff0c;选中下载好的插件&#xff0c;然后重启idea

Unity:删除注册表内的项目记录

然后WinR按键输入regedit 打开注册表 在注册表 HKEY CURRENT USER—>SOFTWARE—>Unity—>UnityEditor—>DefaultCompany —>language_Test 中&#xff0c;删除我们的之前存储的语言环境数据。在 “ 三、文本调用和替换 ” 测试时已经将语言环境存储到注册表中了…

JAVA学习记录3

文章为个人学习记录&#xff0c;仅供参考&#xff0c;如有错误请指出。 上期说到使用记事本编写Java程序太过繁琐&#xff0c;所以我们后面都将使用IDEA进行代码的编写、编译和运行。 如何下载安装IDEA&#xff1f; 这个的下载途径也很多&#xff0c;我还是推荐去官网下载(h…

CSS——22.静态伪类(伪类是选择不同元素状态)

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>静态伪类</title> </head><body><a href"#">我爱学习</a></body> </html>单击链接前的样式 左键单击&#xff08;且…

IDEA中Maven依赖包导入失败报红的潜在原因

在上网试了别人的八个问题总结之后依然没有解决&#xff1a; IDEA中Maven依赖包导入失败报红问题总结最有效8种解决方案_idea导入依赖还是报红-CSDN博客https://blog.csdn.net/qq_43705131/article/details/106165960 江郎才尽之后突然想到一个原因&#xff1a;<dep…

GMDH自组织网络模型时间序列预测,可预测未来

GMDH自组织网络模型时间序列预测&#xff0c;可预测未来 目录 GMDH自组织网络模型时间序列预测&#xff0c;可预测未来效果一览基本介绍模型构建程序设计学习总结参考资料 效果一览 基本介绍 GMDH自组织网络模型是自组织数据挖掘中的一种模型方法&#xff0c;是基于计算机科学和…

【docker系列】可视化Docker 管理工具——Portainer

1. 介绍 Portainer是一个可视化的Docker操作界面&#xff0c;提供状态显示面板、应用模板快速部署、容器镜像网络数据卷的基本操作&#xff08;包括上传下载镜像&#xff0c;创建容器等操作&#xff09;、事件日志显示、容器控制台操作、Swarm集群和服务等集中管理和操作、登录…

Linux/Ubuntu/银河麒麟 arm64 飞腾FT2000 下使用 arm64版本 linuxdeployqt 打包Qt程序

文章目录 一、前言二、环境三、准备1、下载Linuxdeployqt源码2、下载Appimagetool-aarch64.AppImage四、编译linuxdeployqt1.配置环境变量2.编译linuxdeployqt五、安装patchelf六、配置Appimagetool七、打包Qt程序重要提示:测试启动应用八、其他九、最后一、前言 因为项目需要…

pg数据库运维经验2024

这篇文章主要是讲pg运维常见问题&#xff0c;两三年见一次的疑难杂症就不说了。 主要是技术性运维总结&#xff0c;主打通俗易懂和快速上手&#xff0c;尽量避免源码层面等深入分析。 SQL性能与执行计划 执行计划突变 pg官方不支持hint功能&#xff0c;并且计划永远不支持&…

Hadoop 实战笔记(一) -- Windows 安装 Hadoop 3.x

环境准备 安装 JAVA 1.8 Java环境搭建之JDK下载及安装下载 Hadoop 3.3.5 安装包 Hadoop 下载&#xff1a;https://archive.apache.org/dist/hadoop/common/ 一、JAVA JDK 环境检查 二、Hadoop(HDFS)环境搭建 1. 解压安装文件 hadoop-3.3.5.tar 2. 配置环境变量 HADOOP_HO…

个人博客搭建(二)—Typora+PicGo+OSS

个人博客站—运维鹿: http://www.kervin24.top CSDN博客—做个超努力的小奚&#xff1a; 做个超努力的小奚-CSDN博客 一、前言 博客搭建完一直没有更新&#xff0c;因为WordPress自带的文档编辑器不方便&#xff0c;以前用CSDN写作的时候&#xff0c;习惯了Typora。最近对比了…

【向量数据库】搜索算法

最近几年&#xff0c;一种叫做向量数据库的产品&#xff0c;正趁着AI的热潮开始崭露头角。伴随着AI时代的到来&#xff0c;向量将成为一种重要的数据形式&#xff0c;而传统数据库并不适合用来存储和检索向量数据&#xff0c;因此我们大约需要一种专门设计的数据库来处理这些问…

ARM CCA机密计算安全模型之安全生命周期管理

安全之安全(security)博客目录导读 目录 一、固件启用的调试 二、CCA系统安全生命周期 三、重新供应 四、可信子系统与CCA HES 启用 CCA&#xff08;机密计算架构&#xff09;的安全系统是指 CCA 平台的实现处于可信状态。 由于多种原因&#xff0c;CCA 启用系统可能处于不…

k8s排错集:zk集群的pod报错 Init:CrashLoopBackOff无法启动

zk三节点集群&#xff0c;zk-0无法启动 statefulset 进到该node节点上查看容器的报错日志&#xff0c;发现在初始化container的时候一个命令有问题 查看正常zk集群的pod的资源配置文件 解决办法&#xff1a; 修改资源配置文件 应该修改为 chown -R 1000:1000 /zkenv kubec…

Golang的并发编程框架比较

# Golang的并发编程框架比较 中的并发编程 在现代软件开发中&#xff0c;处理高并发的能力愈发重要。Golang作为一门支持并发编程的编程语言&#xff0c;提供了丰富的并发编程框架和工具&#xff0c;使得开发者能够更轻松地处理并发任务。本文将介绍Golang中几种常用的并发编程…

【Web】软件系统安全赛CachedVisitor——记一次二开工具的经历

明天开始考试周&#xff0c;百无聊赖开了一把CTF&#xff0c;还顺带体验了下二开工具&#xff0c;让无聊的Z3很开心&#x1f642; CachedVisitor这题 大概描述一下&#xff1a;从main.lua加载一段visit.script中被##LUA_START##(.-)##LUA_END##包裹的lua代码 main.lua loca…

单纯形法的学习笔记

文章目录 A. 单纯形法概述1. 优化模型示例 B. 理论基础C. 算法思想D. 实现算法1. 线性规划的标准型2. 顶点解的理解及表示2.1 在标准型中变量取值为零的意义2.2 顶点解的表示 3. 最优性判断4. 解的更新5. 完成迭代过程 E. 单纯形法的基本概念与本文对照F. 文档源码 前言&#x…