Java创造型模式之原型模式详解

设计模式是面向对象设计中的一种标准方法,用于解决常见的设计问题。原型设计模式(Prototype Pattern)是23种经典设计模式之一,属于创建型模式,它允许通过复制现有对象来创建新对象,而不是通过构造函数或工厂方法来创建。这样,开发者可以在运行时通过复制原型对象来快速生成新的对象,极大地提高了程序的灵活性和性能。

本文将深入讲解Java中的原型设计模式,解释其概念、使用场景、以及如何在Java中实现。

一、原型设计模式的定义

原型模式是一种通过复制原型对象来创建新对象的设计模式。它使得对象的创建不依赖于具体的类构造,而是依赖于原型实例。原型实例通过浅拷贝或深拷贝的方式复制,从而生成新的实例对象。

关键点:

  1. 原型对象:一个可以复制的对象。
  2. 克隆操作:通过复制(克隆)原型对象来创建新的对象。
  3. 浅拷贝与深拷贝:浅拷贝指的是复制对象时,原对象和复制对象共享引用类型的成员变量。深拷贝则是完全复制对象,确保复制对象和原对象没有任何共享的引用类型变量。

二、使用原型模式的原因

在某些场景中,传统的对象创建方式可能过于复杂或不够高效。通过原型模式,我们可以通过现有的对象(即原型)来快速创建新对象,而无需重新构造对象。

原型模式的优势:

  1. 提高性能:当对象的创建过程比较复杂时,通过原型复制对象来创建新实例通常比使用构造函数更高效。
  2. 简化创建过程:对象的创建不需要重复复杂的初始化操作,只需要通过复制已有对象来实现。
  3. 支持变更:通过复制原型对象,开发者可以在运行时修改对象的某些属性,而不影响原对象。

适用场景:

  • 创建对象的过程较为复杂,且有多个相似对象需要频繁创建时,原型模式尤其有效。
  • 需要在程序运行时动态创建大量相似对象的情况。
  • 在复制对象时不希望重复调用构造函数,特别是当对象初始化代价较大时。

三、原型模式的实现

在Java中,原型模式通常通过实现Cloneable接口来实现,Cloneable接口是Java标准库中的一个标记接口,表示该对象支持克隆操作。Object类中的clone()方法是用于执行浅拷贝的默认实现。

1. 浅拷贝与深拷贝

  • 浅拷贝:复制对象时,只复制对象本身的基本数据类型成员,引用类型成员复制的是地址,意味着原对象和克隆对象会共享引用类型的成员。
  • 深拷贝:复制对象时,不仅复制对象本身,还会复制对象的引用类型成员,确保原对象和克隆对象互不影响。

2. 实现原型模式的步骤

步骤 1:实现 Cloneable 接口

首先,确保要复制的类实现了 Cloneable 接口。Cloneable接口是一个标记接口,它告诉Object.clone()方法该对象支持克隆操作。

步骤 2:重写 clone() 方法

由于Object类的clone()方法是保护的(protected),我们需要在自己的类中覆盖clone()方法。通常我们会将clone()方法设为public,以便外部可以调用。

步骤 3:深拷贝或浅拷贝

根据需求,可以在clone()方法中实现深拷贝或浅拷贝。默认的clone()方法是浅拷贝,如果需要深拷贝,需要手动实现。

四、Java中原型设计模式的示例代码

1、浅拷贝

// 实现Cloneable接口
class Prototype implements Cloneable {private String name;private int age;// 构造方法public Prototype(String name, int age) {this.name = name;this.age = age;}// 获取对象的浅拷贝@Overridepublic Prototype clone() {try {return (Prototype) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}// Getter和Setter方法public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Prototype{" +"name='" + name + '\'' +", age=" + age +'}';}
}public class PrototypeDemo {public static void main(String[] args) {// 创建原型对象Prototype original = new Prototype("Alice", 30);System.out.println("Original Object: " + original);// 克隆原型对象Prototype clone = original.clone();System.out.println("Cloned Object: " + clone);// 修改克隆对象的属性clone.setName("Bob");clone.setAge(25);System.out.println("Modified Cloned Object: " + clone);System.out.println("Original Object after modification: " + original);}
}

结果为: 

Original Object: Prototype{name='Alice', age=30}
Cloned Object: Prototype{name='Alice', age=30}
Modified Cloned Object: Prototype{name='Bob', age=25}
Original Object after modification: Prototype{name='Alice', age=30}

2、深拷贝

class Address {private String street;private String city;public Address(String street, String city) {this.street = street;this.city = city;}public Address(Address address) {this.street = address.street;this.city = address.city;}@Overridepublic String toString() {return "Address{" +"street='" + street + '\'' +", city='" + city + '\'' +'}';}
}class DeepPrototype implements Cloneable {private String name;private Address address;public DeepPrototype(String name, Address address) {this.name = name;this.address = address;}@Overridepublic DeepPrototype clone() {try {DeepPrototype cloned = (DeepPrototype) super.clone();cloned.address = new Address(this.address); // 深拷贝return cloned;} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}@Overridepublic String toString() {return "DeepPrototype{" +"name='" + name + '\'' +", address=" + address +'}';}
}public class DeepPrototypeDemo {public static void main(String[] args) {Address address = new Address("Baker Street", "London");DeepPrototype original = new DeepPrototype("John", address);System.out.println("Original Object: " + original);// 深拷贝原型对象DeepPrototype cloned = original.clone();System.out.println("Cloned Object: " + cloned);// 修改克隆对象的属性cloned.address = new Address("Wall Street", "New York");System.out.println("Modified Cloned Object: " + cloned);System.out.println("Original Object after modification: " + original);}
}

结果为:

Original Object: DeepPrototype{name='John', address=Address{street='Baker Street', city='London'}}
Cloned Object: DeepPrototype{name='John', address=Address{street='Baker Street', city='London'}}
Modified Cloned Object: DeepPrototype{name='John', address=Address{street='Wall Street', city='New York'}}
Original Object after modification: DeepPrototype{name='John', address=Address{street='Baker Street', city='London'}}

五、总结

原型设计模式通过克隆现有对象来创建新对象,而不是每次都通过构造函数创建。这种方式非常适合需要频繁创建相似对象的场景。Java提供了Cloneable接口和clone()方法来支持该模式的实现。在实际开发中,使用原型模式可以减少对象创建时的性能开销,同时也可以在对象状态变化时避免重复操作。

无论是浅拷贝还是深拷贝,原型模式都能有效提高开发效率,并在某些情况下避免不必要的资源浪费。理解并合理使用原型模式,可以在复杂系统的设计中发挥重要作用。

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

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

相关文章

python-leetcode 54.全排列

题目: 给定不含重复数字的数组nums,返回其所有可能的全排列,可以按任意顺序返回答案 回溯法 一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解(或者至少不是最后一个解),回溯算法会通…

python局部变量和全局变量

文章目录 1.局部变量和全局变量2.局部变量2.1 局部变量的作用2.2 局部变量的生命周期 3. 全局变量3.1 函数不能直接修改全局变量的引用3.2 在函数内部修改全局变量的值3.3 全局变量定义的位置3.4 全局变量命名的建议 1.局部变量和全局变量 (1)局部变量 …

华为中小型企业项目案例

实验目的(1) 熟悉华为交换机和路由器的应用场景 (2) 掌握华为交换机和路由器的配置方法 实验拓扑实验拓扑如图所示。 华为中小型企业项目案例拓扑图 实验配置市场部和技术部的配置创建VLANLSW1的配置 [LSW1]vlan batch 10 20 [LSW1]q…

深度学习-简介

一、几个概念 (1)what is ai including? 看一张图: 这里注意机器学习和深度学习的关系 (2)机器学习和模式识别有什么区别? 和机器学习同领域的有一个词叫做模式识别,二者有什么区别呢? 机…

Unity小框架之单例模式基类

单例模式(Singleton Pattern)是一种常用的创建型设计模式,其核心目标是确保一个类只有一个实例,并提供一个全局访问点。它常用于需要控制资源访问、共享配置或管理全局状态的场景(如数据库连接池、日志管理器、应用配置…

安装 Powerlevel10k 及 Oh My Zsh 的使用

1. 简介 Powerlevel10k 是 Oh My Zsh 最流行的终端主题,它不仅美观,还提供 Git 状态显示、命令执行时间、网络状态、Python 虚拟环境指示等 实用功能。相比其他主题,Powerlevel10k 速度更快、可定制性更强。 本教程将详细介绍如何安装 Powe…

verilog有符号数处理摘要

在FPGA设计中,一般的算数运算符都是按照无符号数进行的。那么需要有符号数计算的时候,该怎么办呢? 很久很久以前也就是Verilog-2001还没有出现时,是手动操作的,也就是说,对于一个8位的无符号数&#xff0c…

在IDEA中连接达梦数据库:详细配置指南

达梦数据库(DM Database)作为国产关系型数据库的代表,广泛应用于企业级系统开发。本文将详细介绍如何在IntelliJ IDEA中配置并连接达梦数据库,助力开发者高效完成数据库开发工作。 准备工作 1. 下载达梦JDBC驱动 访问达梦官方资…

app.config.globalProperties

目录 一:基础使用 1、简介 2、使用 3、打印结果: 二:封装 1、创建一个.ts文件(utils/msg.ts) 2、在main.ts中全局注册 3、在页面中使用 4、打印结果 一:基础使用 1、简介 app.config.globalProperties 是 Vue 3 应用实例(app)的一个配置属性&…

openai 标准化协议 Structured Outputs 具体示例教程

Structured Outputs 具体示例教程 场景:个人财务管理助手 假设我们要构建一个 AI 助手,帮助用户记录和管理个人财务支出。用户可以输入自然语言描述(如“昨天我花了50元买了午餐”),助手将提取关键信息并以结构化 JS…

16.使用读写包操作Excel文件:XlsxWriter 包

一 XlsxWriter 的介绍 XlsxWriter 只能写入 Excel 文件。 OpenPyXL 和 XlsxWriter 的区别在笔记 15 。 二 如何使用 XlsxWriter 1.导包 import datetime as dtimport xlsxwriterimport excel 2.实例化工作簿 book xlsxwriter.Workbook("xlxswriter.xlsx") book.clo…

ChatGPT and Claude国内使用站点

RawChat kelaode chatgptplus chatopens(4.o mini免费,plus收费) 网页: 定价: wildcard 网页: 虚拟卡定价: 2233.ai 网页: 定价: MaynorAPI chatgpt cla…

【MySQL】MySQL审计工具Audit Plugin安装使用

MySQL审计工具Audit Plugin安装使用 https://www.cnblogs.com/waynechou/p/mysql_audit.html MySQL 5.6 开启审计功能 https://blog.51cto.com/u_15127556/4344503 MySQL之添加日志审计功能 https://blog.csdn.net/weixin_43279032/article/details/105507170 MySQL开启日志记录…

QT 磁盘文件 教程04-创建目录、删除目录、遍历目录

【1】新建目录 bool CreateDir(QString name){QString fileName name ;QDir dir(fileName);if (dir.isEmpty()) {dir.mkdir(fileName);return true;}else{qDebug()<<"文件夹已存在";return false;} } 【2】删除目录 bool DeleteDir(QString fileName){if (…

Git——分布式版本控制工具使用教程

本文主要介绍两种版本控制工具——SVN和Git的概念&#xff0c;接着会讲到Git的安装&#xff0c;Git常用的命令&#xff0c;以及怎么在Vscode中使用Git。帮助新手小白快速上手Git。 1. SVN和Git介绍 1.1 SVN 集中式版本控制工具&#xff0c;版本库是集中存放在中央服务器的&am…

Vue:添加响应式数据

Vue&#xff1a;添加响应式数据 1. 什么是响应式&#xff1f; 修改 data 后&#xff0c;页面自动改变/刷新&#xff0c;这就是响应式。就像我们在使用 Excel 的时候&#xff0c;修改一个单元格中的数据&#xff0c;其它单元格的数据会联动更新&#xff0c;这也是响应式。在前…

算法刷题记录——LeetCode篇(10) [第901~1000题](持续更新)

(优先整理热门100及面试150&#xff0c;不定期持续更新&#xff0c;欢迎关注) 994. 腐烂的橘子 在给定的 m x n 网格 grid 中&#xff0c;每个单元格可以有以下三个值之一&#xff1a; 值 0 代表空单元格&#xff1b;值 1 代表新鲜橘子&#xff1b;值 2 代表腐烂的橘子。 每…

Secs/Gem第二讲 (基于secs4net项目的ChatGpt介绍)

好的&#xff0c;我们正式进入&#xff1a; 第二讲&#xff1a;深入 SECS4NET 项目结构——主机程序是怎么搭起来的&#xff1f; 关键词&#xff1a;项目结构、类图、通信类、事件处理、连接生命周期、异步机制 本讲目的 我们从源码入手&#xff0c;一步步搞懂&#xff1a; S…

压测实战 | 微信小程序商城 “双 11” 的压测实践

背景 某全球知名珠宝品牌&#xff0c;始终以创新驱动零售变革。随着全渠道战略的深化&#xff0c;其小程序官方商城逐渐成为品牌私域流量的核心阵地&#xff0c;不仅承载了线上销售、会员运营等功能&#xff0c;同时还与其内部系统打通&#xff0c;如会员管理系统、人力资源系…

垃圾分类--环境配置

写在前面&#xff1a; 如果你们打这届比赛时&#xff0c;还有我们所保留的内存卡&#xff0c;那么插上即可运行&#xff08;因为内存卡里我们已经配置好所有的环境&#xff09; 本文提供两种环境的配置 一种是基于yolov8&#xff1a;YOLOv8 - Ultralytics YOLO Docshttps://d…