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

原型模式简介

概念

原型模式 (Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而无需依赖于昂贵的实例化过程。该模式基于原型实例生成新的对象,并且可以根据需要进行修改和定制。

特点

  1. 通过克隆已有对象来创建新对象,避免了重复的初始化过程。
  2. 可以动态地添加或删除已有的原型。
  3. 提供了一种简单、灵活和高效的方式来创建多个相似对象。

优点

  1. 减少了重复代码,提高了代码复用性。
  2. 避免了耗时的实例化操作,提升性能。
  3. 简化了对象创建过程,使得系统更加灵活。

缺点

  1. 需要为每个可变属性添加适当的克隆方法,并在每次修改时更新这些方法。
  2. 如果存在循环引用,则需要小心处理克隆过程中可能出现的无限循环问题。

适用场景

  1. 当一个系统需要独立于其具体类型创建多个相似但不同配置项或版本时,可以使用原型模式。
  2. 当一个系统需要动态地加载和配置类实例时,可以使用原型模式。

实现方式

浅拷贝:

直接对目标对象进行浅拷贝,复制基本数据类型的值和引用类型的地址。

实现原理

  1. 创建一个新对象,并将原始对象中所有的字段值复制给新对象。
  2. 对于基本数据类型,直接进行值复制。
  3. 对于引用类型,只复制其地址而不创建新的实例。

实现代码:

import java.util.ArrayList;
import java.util.List;class Prototype implements Cloneable {private int id;private String name;private List<String> list;// 构造函数public Prototype(int id, String name, List<String> list) {this.id = id;this.name = name;this.list = list;}// Getter 和 Setterpublic void setList(List<String> list) {this.list = list;}public List<String> getList(){return this.list;}@Overridepublic Prototype clone() throws CloneNotSupportedException {return (Prototype) super.clone();}
}public class Main {public static void main(String[] args) {List<String> originalList = new ArrayList<>();originalList.add("item1");originalList.add("item2");Prototype originalObject = new Prototype(1, "Original", originalList);try {Prototype clonedObject = originalObject.clone();System.out.println(originalObject == clonedObject); // 输出 falseSystem.out.println(originalObject.getList() == clonedObject.getList()); // 输出 true} catch (CloneNotSupportedException e) {e.printStackTrace();}}
}

在上述示例中,Prototype 类实现了 Cloneable 接口,并重写了 clone() 方法。通过调用 super.clone() 进行浅拷贝操作,返回一个新的克隆对象。

接下来我们创建了一个原始对象 originalObject,并进行浅拷贝得到克隆对象 clonedObject。可以观察到两个对象不相等(因为引用地址不同),但是它们共享相同的引用类型字段(即列表),所以对列表的修改会同时影响两个对象。

存在问题
由于浅拷贝仅仅是对引用进行了简单地复制操作,并没有创建全新独立的副本,因此可能会导致以下问题:

  1. 如果被复制的引用类型发生改变,那么克隆后得到的副本也会受到影响。
  2. 在多层嵌套结构中,如果某个属性发生改变,则克隆后得到副本中对应属性也会改变。

深拷贝:

对目标对象进行深拷贝,复制基本数据类型的值和引用类型的整个对象。

实现原理

  1. 创建一个新对象,并将原始对象中所有字段值复制给新对象。
  2. 对于基本数据类型,直接进行值复制。
  3. 对于引用类型,在克隆过程中创建该引用类型的全新副本,并将副本赋值给新对象。

实现代码

import java.util.ArrayList;
import java.util.List;class Prototype implements Cloneable {private int id;private String name;private List<String> list;// 构造函数public Prototype(int id, String name, List<String> list) {this.id = id;this.name = name;this.list = list;}// Getter 和 Setterpublic List<String> getList() {return list;}public void setList(List<String> list) {this.list = list;}@Overridepublic Prototype clone() throws CloneNotSupportedException {Prototype clonedObject = (Prototype) super.clone();clonedObject.list = new ArrayList<>(this.list); // 创建全新副本return clonedObject;}
}public class Main {public static void main(String[] args) {List<String> originalList = new ArrayList<>();originalList.add("item1");originalList.add("item2");Prototype originalObject = new Prototype(1, "Original", originalList);try {Prototype clonedObject = originalObject.clone();System.out.println(originalObject == clonedObject); // 输出 falseSystem.out.println(originalObject.getList() == clonedObject.getList()); // 输出 false} catch (CloneNotSupportedException e) {e.printStackTrace();}}
}

在上述示例中,Prototype 类实现了 Cloneable 接口,并重写了 clone() 方法。通过调用 super.clone() 进行浅拷贝操作,然后对引用类型字段进行深层次克隆。

接下来我们创建了一个原始对象 originalObject,并进行深拷贝得到克隆对象 clonedObject。可以观察到两个对象完全独立(因为引用地址不同),它们的列表也是独立的副本,所以对列表的修改不会相互影响。

深拷贝虽然解决了浅拷贝可能带来的问题,但也存在以下问题:

  1. 如果被复制的引用类型内部还包含其他引用类型,则需要递归地进行深层次克隆操作。
  2. 某些类可能无法被序列化或反序列化而导致无法使用标准方法实现深拷贝。

原型注册表

使用原型管理器来存储和获取原型实例,可以通过名称或标识符查找并克隆相应的原型。

实现原理

  1. 创建一个原型注册表类(通常为单例),用于存储和管理多个不同类型的原型对象。
  2. 在注册表中添加方法,用于向注册表中添加、删除或获取指定名称的原型对象。
  3. 当客户端需要创建新对象时,可以通过调用注册表中相应名称的方法来获取对应的克隆副本。

实现代码

import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;class Prototype implements Cloneable {private int id;private String name;private List<String> list;// 构造函数public Prototype(int id, String name, List<String> list) {this.id = id;this.name = name;this.list = list;}// Getter 和 Setterpublic void setName(String name){this.name = name;}public String getName() {return this.name;}public List<String> getList() {return list;}public void setList(List<String> list) {this.list = list;}@Overridepublic Prototype clone() throws CloneNotSupportedException {Prototype clonedObject = (Prototype) super.clone();clonedObject.list = new ArrayList<>(this.list); // 创建全新副本return clonedObject;}
}class PrototypeRegistry {private static PrototypeRegistry instance;private Map<String, Prototype> prototypes;private PrototypeRegistry() {prototypes = new HashMap<>();}public static synchronized PrototypeRegistry getInstance() {if (instance == null) {instance = new PrototypeRegistry();}return instance;}public void addPrototype(String name, Prototype prototype) {prototypes.put(name, prototype);}public void removePrototype(String name) {prototypes.remove(name);}public Prototype getPrototype(String name) throws CloneNotSupportedException {Prototype prototype = prototypes.get(name);if (prototype != null) {return prototype.clone();}return null;}
}public class Main {public static void main(String[] args) {
// 创建原始对象并添加到注册表List<String> originalList = new ArrayList<>();originalList.add("item1");originalList.add("item2");Prototype originalObject = new Prototype(1, "Original", originalList);PrototypeRegistry registry = PrototypeRegistry.getInstance();registry.addPrototype("object1", originalObject);// 从注册表获取副本并进行修改try {Prototype clonedObject = registry.getPrototype("object1");if (clonedObject != null) {clonedObject.setName("Cloned");System.out.println(originalObject.getName()); // 输出 "Original"System.out.println(clonedObject.getName()); // 输出 "Cloned"System.out.println(originalObject.getList() == clonedObject.getList()); // 输出 false}} catch (CloneNotSupportedException e) {e.printStackTrace();}}
}

在深拷贝实现代码的基础上,我们增加了PrototypeRegistry 类实现了原型注册表的功能。通过使用单例模式保证只有一个注册表实例,并使用 HashMap 存储原型对象。然后创建了一个原始对象 originalObject 并将其添加到注册表中。然后通过调用 getPrototype() 方法从注册表中获取副本,并对副本进行修改。可以观察到两个对象是独立的,对一个对象的修改不会影响到另一个对象。

序列化与反序列化

将对象序列化为字节流,然后再反序列化为新对象。

实现原理

  1. 被克隆的对象必须实现 Serializable 接口。
  2. 序列化:使用 ObjectOutputStream 将对象写入输出流,并将其转换为字节数组。
  3. 反序列化:使用 ObjectInputStream 从输入流中读取字节数组,并将其转换回原始对象。

实现代码

import java.io.*;
import java.util.ArrayList;
import java.util.List;class Prototype implements Serializable {private int id;private String name;private List<String> list;// 构造函数public Prototype(int id, String name, List<String> list) {this.id = id;this.name = name;this.list = list;}// Getter 和 Setterpublic List<String> getList() {return list;}public Prototype deepClone() {try {ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(this);ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);return (Prototype) ois.readObject();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}return null;}
}public class Main {public static void main(String[] args) {List<String> originalList = new ArrayList<>();originalList.add("item1");originalList.add("item2");Prototype originalObject = new Prototype(1, "Original", originalList);Prototype clonedObject = originalObject.deepClone();System.out.println(originalObject == clonedObject); // 输出 falseSystem.out.println(originalObject.getList() == clonedObject.getList()); // 输出 false}
}

在上述示例中,Prototype 类实现了 Serializable 接口,并提供了一个 deepClone() 方法来进行深拷贝。在该方法中,首先将对象写入输出流并转换为字节数组,然后再从输入流中读取字节数组并转换回对象。然后我们创建了一个原始对象 originalObject 并通过调用 deepClone() 方法进行深拷贝得到副本对象 clonedObject。可以观察到两个对象是独立的(因为引用地址不同),它们的列表也是独立的副本,所以对列表的修改不会相互影响。需要注意的是当被克隆的类包含不可被序列化或反序列化的字段(如线程、文件句柄等),则需要采取额外措施来处理这些字段。

相关文章:

原型模式简介

概念&#xff1a; 原型模式 (Prototype Pattern)是一种创建型设计模式&#xff0c;它允许通过复制现有对象来创建新对象&#xff0c;而无需依赖于昂贵的实例化过程。该模式基于原型实例生成新的对象&#xff0c;并且可以根据需要进行修改和定制。 特点&#xff1a; 通过克隆…...

SpringMVC(一)

1.SpringMVC简介 1.1 什么是MVC MVC是一种软件架构的思想&#xff0c;将软件按照模型、视图、控制器来划分 M:Model,模型层&#xff0c;指工程中的JavaBean,作用是处理数据 JavaBean分为两类&#xff1a; 一类称为实体类Bean:专门存储业务逻辑的&#xff0c;如Student、Us…...

树的基本概念和存储结构

一、树的基本概念 1、树的定义 树是n&#xff08;n>0&#xff09;个结点的有限集。当n 0时&#xff0c;称为空树。在任意一棵非空树中应满足&#xff1a; 1、有且仅有一个特定的称为根的结点。 2、当n>1时&#xff0c;其余节点可分为m&#xff08;m>0&#xff09…...

深圳企业制作宣传片群体定位的重要性

相信众多企业都拍了自己公司的宣传片&#xff0c;尤其是在互联网高度发达的今天&#xff0c;宣传片可以说成为了我们企业对外宣传最主要的方式。看着企业多样式的宣传片种类&#xff0c;我们该如何评价一部宣传片的好坏呢&#xff1f;要知道宣传片的好坏是一个相对主观的问题&a…...

2309亚当arsd的11.1版本

原文 arsd11.1 Minigui 调整主题 在11.0中略有修改Minigui的主题,但它落后于11.1的计划.这是个重大更改,但这些更改很小. 新主题稍微变浅了默认组件的背景色和默认字体,这两者都主要影响Linux,因为窗口上的大多数组件一般使用本地主题. 更改状态栏 现有的状态栏类允许添加…...

spring---第七篇

系列文章目录 文章目录 系列文章目录一、什么是bean的自动装配,有哪些方式?一、什么是bean的自动装配,有哪些方式? 开启自动装配,只需要在xml配置文件中定义“autowire”属性。 <bean id="cutomer" class="com.xxx.xxx.Customer" autowire="…...

编程要搞明白的东西(二)

文章目录 一、简介二、面向对象编程基础2.1 面向对象编程概述2.2 类和对象2.2.1 类的定义和特点2.2.2 对象的创建和使用 2.3 封装、继承与多态的关系2.3.1 封装的概念和优势2.3.2 继承的概念和作用2.3.3 多态的概念和实现方式 三、封装3.1 封装的定义和原则3.2 封装的实现方法3…...

检索与毒害 —— 对抗人工智能供应链攻击

作者&#xff1a;DAVE ERICKSON 在这篇文章中&#xff0c;了解人工智能大语言模型的供应链漏洞&#xff0c;以及如何利用搜索引擎的人工智能检索技术来对抗人工智能的错误信息和故意篡改。 虽然对于人工智能研究人员来说可能是新鲜事&#xff0c;但供应链攻击对于网络安全世界…...

Linux 禁止用户或 IP通过 SSH 登录

Linux 禁止用户或 IP通过 SSH 登录 限制用户 SSH 登录 1.只允许指定用户进行登录(白名单): 在 /etc/ssh/sshd_config 配置文件中设置 AllowUsers 选项,(配置完成需要重启 SSHD 服务)格式如下: AllowUsers aliyun test@192.168.1.1 # 允许 aliyun 和从 19…...

14.Redis 主从复制

Redis 主从复制 redis 主从复制配置 redis 主从复制启动 redis 主从复制断开 redis 主从复制主从复制构特点主从复制的拓扑结构一主一从⼀主多从树状主从 主从复制原理数据同步psync 运行流程全量复制流程部分复制流程实时复制 关于从节点何时晋升成主节点总结 redis 主从复制 …...

常见的图像格式介绍:RAW、RGB、YUV

常见的图像格式有RAW、RGB、YUV这三大类 1. RAW raw图像指的是sensor输出的原始数据&#xff0c;常见的有8位、10位、12位之分&#xff0c;分别表示一个像素点所占的字节数为8bit、10bit、12bit。 raw数据常见的有四种Bayer模式&#xff1a;GRBG、RGGB、BGGR&#xff08;下图…...

极简极速-Bitset (bitmap)实现考勤打卡场景

文章目录 1. redis命令行操作bitmap2. RedisTemplate操作bitmap3. Java中的Bitset 1. redis命令行操作bitmap 2. RedisTemplate操作bitmap bitmap的常见业务场景主要有日活统计&#xff08;类似的月考勤&#xff09;、点赞、BloomFilter等&#xff0c;以用户mj考勤统计为例&am…...

word如何插入图片?3种常用的方法

word作为一款常用的办公软件&#xff0c;不仅可以处理文本内容&#xff0c;还能够轻松地插入图片以丰富文档内容。插入图片可以使文档更具吸引力、可读性和信息传达能力。本文将为您介绍word如何插入图片的3种方法&#xff0c;帮助您在文档中灵活、高效地添加图像元素。 word插…...

Python/C API - 模組,型別,Tuple,例外和引用計數

Python/C API - 模組&#xff0c;型別&#xff0c;Tuple&#xff0c;例外和引用計數 前言Python/C API - Common Object StructuresPyObjectPyMethodDefPyGetSetDef Python/C API - Module ObjectsPyModuleDefPyModule_CreatePyModule_AddObjectPyModule_AddObjectRef Initiali…...

人工智能轨道交通行业周刊-第59期(2023.9.4-9.10)

本期关键词&#xff1a;无锡智慧地铁、无人车站、钢轨打磨、混元大模型、开源大模型 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro轨道世界…...

ASP.NET Core 中的 MVC架构

MVC 架构 MVC架构把 App 按照逻辑分成三层&#xff1a; Controllers&#xff0c;接收 http request&#xff0c;配合 model&#xff0c;通过http response 返回 view&#xff0c;尽量不做别的事Models, 负责业务逻辑&#xff0c;App 的状态&#xff0c;以及数据处理Views&…...

C# PSO 粒子群优化算法 遗传算法 随机算法 求解复杂方程的最大、最小值

复杂方程可以自己定义&#xff0c;以下是看别人的题目&#xff0c;然后自己来做 以下是计算结果 private void GetMinResult(out double resultX1, out double min){double x1, result;Random random1 new Random(DateTime.Now.Millisecond* DateTime.Now.Second);min 99999…...

网络协议从入门到底层原理学习(三)—— 路由

网络协议从入门到底层原理学习&#xff08;三&#xff09;—— 路由 1、简介 路由&#xff08;routing&#xff09;是指分组从源到目的地时&#xff0c;决定端到端路径的网络范围的进程 在不同网段之间转发数据&#xff0c;需要有路由器的支持 默认情况下&#xff0c;路由器…...

2023/9/6 -- C++/QT

一、输出流对象cout 1> 该对象是来自于ostream的类对象&#xff0c;功能上类似于printf函数 2> 该类对象本质上调用成员函数插入运算符重载函数 3> 输出数据时&#xff0c;无需使用格式控制符&#xff1a;%d、%c、%s。。。&#xff0c;直接输出即可 4> 换行使用…...

python爬虫,多线程与生产者消费者模式

使用队列完成生产者消费者模式使用类创建多线程提高爬虫速度 https://sc.chinaz.com/tupian/index.html https://sc.chinaz.com/tupian/index_2.html https://sc.chinaz.com/tupian/index_3.html from threading import Thread from queue import Queue import requests from b…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...

PHP 8.5 即将发布:管道操作符、强力调试

前不久&#xff0c;PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5&#xff01;作为 PHP 语言的又一次重要迭代&#xff0c;PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是&#xff0c;借助强大的本地开发环境 ServBay&am…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...