【原型模式】

news/2024/9/19 0:41:46/ 标签: 原型模式

原型模式 Prototype Pattern

  • 属于创建型模式
  • 是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,调用者不需要知道任何创建细节,不调用构造函数
  • 关键点:不通过 new 关键字,而是通过方法去创建对象

原型模式的使用场景

  • 类初始化消耗资源较多
  • new 产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
  • 构造函数比较复杂
  • 循环体中生产大量对象

通过硬编码复制对象

编写比较麻烦

@Data
public class User {private Long id;private String name;private String pwd;private String addr;private String mobile;private int age;// ... 属性非常多 .../*** 硬编码复制*/public User copy() {User user = new User();user.setId(this.getId());user.setName(this.getName());user.setPwd(this.getPwd());user.setAddr(this.getAddr());user.setMobile(this.getMobile());user.setAge(this.getAge());// ...这里还有很多属性set...return user;}}

通过反射复制对象

本质也是 set、get

public static Object copy(Object prototype) {Class<?> clazz = prototype.getClass();Object returnValue;try {returnValue = clazz.newInstance();// 获取所有属性, 并设置可访问for (Field field : clazz.getDeclaredFields()) {field.setAccessible(true);field.set(returnValue, field.get(prototype));}} catch (Exception e) {throw new RuntimeException(e);}return returnValue;
}

浅拷贝复制对象

浅拷贝的特点

  • 对于基本类型是按值复制,不会因为原对象的基本类型值的改变而影响到拷贝后的对象
  • 对于引用类型,prototype 和 clone 对象引用同一个引用类型对象(复制引用对象的内存地址)

浅拷贝存在的问题

  • 修改 clone[prototype] 引用的对象后,会影响到 prototype[clone]
@Data
public class ConcretePrototype implements Cloneable {private String name;private int age;private List<String> hobbies;/*** 实现 Cloneable 接口, 底层使用字节码进行克隆*/@Overridepublic ConcretePrototype clone() {try {// TODO: copy mutable state here, so the clone can't change the internals of the originalreturn (ConcretePrototype) super.clone();} catch (CloneNotSupportedException e) {throw new AssertionError();}}
}

测试及结果
修改 prototype 的 hobbies 后,clone 的 hobbies 也被修改了

public static void main(String[] args) {ShallowConcretePrototype prototype = new ShallowConcretePrototype();prototype.setAge(20);prototype.setName("yes");ArrayList<String> hobbies = new ArrayList<>();hobbies.add("书法");hobbies.add("象棋");prototype.setHobbies(hobbies);ShallowConcretePrototype clone = prototype.clone();System.out.println("prototype == clone : " + (prototype == clone));prototype.setAge(25);System.out.println("==== 修改基本类型 age ====");System.out.println(prototype);System.out.println(clone);prototype.hobbies.add("游戏");System.out.println("prototype.hobbies == clone.hobbies : " + (prototype.hobbies == clone.hobbies));System.out.println("==== 修改引用类型 hobbies ====");System.out.println(prototype.hobbies);System.out.println(clone.hobbies);System.out.println("prototype.hobbies == clone.hobbies : " + (prototype.hobbies == clone.hobbies));
}

流实现深拷贝复制对象

@Data
public class DeepConcretePrototype implements Serializable
, Cloneable {private String name;private int age;private List<String> hobbies;@Overridepublic DeepConcretePrototype 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 (DeepConcretePrototype)ois.readObject();} catch (Exception e) {throw new RuntimeException(e);}}
}

测试及结果

public static void main(String[] args) {DeepConcretePrototype prototype = new DeepConcretePrototype();prototype.setAge(20);prototype.setName("yes");ArrayList<String> hobbies = new ArrayList<>();hobbies.add("书法");hobbies.add("象棋");prototype.setHobbies(hobbies);DeepConcretePrototype clone = prototype.clone();System.out.println("prototype == clone : " + (prototype == clone));prototype.setAge(25);System.out.println("==== 修改基本类型 age ====");System.out.println(prototype);System.out.println(clone);prototype.hobbies.add("游戏");System.out.println("prototype.hobbies == clone.hobbies : " + (prototype.hobbies == clone.hobbies));System.out.println("==== 修改引用类型 hobbies ====");System.out.println(prototype.hobbies);System.out.println(clone.hobbies);System.out.println("prototype.hobbies == clone.hobbies : " + (prototype.hobbies == clone.hobbies));
}

json 字符串实现深拷贝复制对象

todo

防止单例被原型模式破坏

1、单例类不实现 cloneable 接口
2、实现 cloneable,但是 clone 方法直接返回单例对象

原型模式在源码中的应用

ArrayList
HashMap

总结

优点:

  • 性能优良,Java 自带的原型模式是基于二进制流的拷贝,比直接 new 一个对象性能上提升了许多
  • 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,简化了创建过程

缺点:

  • 必须匹配克隆方法
  • 当对已有类进行改造的时候,需要修改代码,违反了开闭原则
  • 深拷贝、浅拷贝需要运用得当

via

https://www.bilibili.com/video/BV1nZ4y1i7tn?p=6


http://www.ppmy.cn/news/1519836.html

相关文章

高职院校人工智能训练师边缘计算实训室建设方案

一、引言 随着人工智能技术的飞速发展&#xff0c;边缘计算在提升数据处理效率、降低延迟、保护数据安全等方面展现出巨大潜力。高职院校作为技能型人才培养的重要基地&#xff0c;建设人工智能训练师边缘计算实训室&#xff0c;旨在培养掌握前沿技术、具备实战能力的复合型人才…

自定义Shell程序(内附源码)

在这篇博客中&#xff0c;我们将深入探讨如何自行编写一个简单的Shell程序&#xff0c;我们的示例程序是一个用C语言编写的名为myshell的小型命令行界面。这个项目不仅是对操作系统如何通过命令行与用户互动的一个实用介绍&#xff0c;同时也展示了环境变量、进程创建和命令解析…

Python 全栈系列265 使用ORM、Kafka、Apscheduler实现任务的并发处理

说明 这次的尝试&#xff0c;从框架来说是比较成功的。但是不太走运的是&#xff0c;有一个小的磁盘回收没有写&#xff0c;结果在我外出旅游的时候磁盘打满&#xff0c;导致任务没有按预期执行完&#xff0c;这点比较遗憾。 这里快速把实现的框架梳理一下&#xff0c;后续可…

差旅游记|绵阳:生活的意义在于体验

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 几年前在微博上有个段子广为流传&#xff0c;说是梁朝伟哪天烦闷了&#xff0c;就去机场&#xff0c;赶上哪班就搭哪班&#xff0c;比如去伦敦广场晒太阳&#xff0c;发呆&#xff0c;喂鸽子&#xff0c;完了再搭最近…

Azure Data Factory 多选选项集不受支持

在用ADF往外部推数据时&#xff0c;会碰到CRM的一种数据类型&#xff0c;多选下拉框&#xff0c;如下图中的 如果我们把多选字段输入源字段中&#xff0c;会得到如下的提示 查询官方文档&#xff0c;则有如下的说法 所以把值往外推就需要变通下&#xff0c;例如使用一个文本字段…

爬虫:爬取MDPI杂志中国作者单位和邮箱

Python爬虫&#xff0c;简单来说&#xff0c;就是使用Python编程语言编写的一种自动化获取网页内容的程序。它们能够模拟人类浏览网页的行为&#xff0c;如访问网页、解析网页内容、甚至填写表单和点击链接等&#xff0c;从而帮助我们从互联网上大量收集和处理数据。Python爬虫…

dart 字符串截取

截取 String str "500001"; String lastThreeDigits str.substring(str.length - 3);在这个例子中&#xff0c;str.length - 3计算的是开始截取的索引位置&#xff0c;它从字符串的倒数第三个字符开始截取&#xff0c;一直到字符串的末尾。因此&#xff0c;lastTh…

Nginx学习(第二天)

一.Nginx高级配置 1.1 Nginx状态页 基于nginx 模块 ngx_http_stub_status_module 实现&#xff0c; 在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module 否则配置完成之后监测会是提示法错误 注意: 状态页显示的是整个服务器的状态,而非虚拟主机的状态 …

运维问题0001:MM模块-MIGO收货报错“消息号 M7036 对于采购订单********无收货可能”

1、问题解析&#xff1a; 该报错为SAP标准报错类型,针对公司不同配置/业务设计/校验逻辑&#xff0c;导致该问题原因比较多。 常见的问题总结如下&#xff1a; 1&#xff09;输入的PO信息有问题&#xff08;例如&#xff1a;PO输入错误/PO删除状态/PO冻结状态/PO已完成收货等…

【Next】3. 开发规范

笔记来源&#xff1a;编程导航 1、约定式路由 Next.js 使用 约定式路由&#xff0c;根据文件夹的结构和名称&#xff0c;自动将对应的 URL 地址映射到页面文件。 常见的几种路由规则如下&#xff1a; 1&#xff09;基础规则&#xff1a;以 app 目录作为根路径&#xff0c;根…

企微获客链接 中文乱码问题处理

企微获客链接 中文乱码问题处理 问题背景问题处理补充内容 问题背景 为了推广产品&#xff0c;同时更好的服务客户&#xff0c;公司在接入企业微信后&#xff0c;需要用到企微获客链接相关推广操作&#xff0c;那么通过API 接口创建企微获客链接时&#xff0c;出现了中文乱码问…

MYSQL————联合查询

联合多个表进行查询 设计数据时把表进行拆分&#xff0c;为了消除表中字段的依赖关系&#xff0c;比如部分函数依赖&#xff0c;传递依赖&#xff0c;这时会导致一条SQL查出来的数据&#xff0c;对于业务来说是不完整的&#xff0c;我们就可以使用联合查询把关系中的数据全部查…

Java 入门指南:Java 并发编程 —— Condition 灵活管理线程间的同步

Condition Condition 是 Java 并发编程中的一种高级同步工具&#xff0c;它可以协助线程之间进行等待和通信。提供了一种比传统的 wait() 和 notify() 更加灵活的方式来管理线程间的同步。Condition 接口通常与 Lock 接口一起使用&#xff0c;允许更细粒度的控制线程的等待和唤…

DNS服务器的配置(服务名named,端口53)

目录 前言 配置文件 DNS服务器的配置 主配置文件 扩展配置文件 区域配置文件 重启服务 配置防火墙 配置客户端dns 前言 DNS服务器的主要作用是将人类可读的域名转换为机器可读的IP地址&#xff0c;从而方便用户访问互联网资源。 在互联网中&#xff0c;设备需要通过I…

前端性能优化:使用Vue3+TS+Canvas对图片进行压缩后再上传,优化带宽,减小服务器存储成本,减少流量损耗

在上传图片之前&#xff0c;对图片进行压缩。看到这里是不是有点懵&#xff0c;前端怎么压缩图片呢&#xff0c;这不应该是后端做的吗&#xff1f; 但是我在开发的时候接到了这样一个需求&#xff0c;要求对用户上传的图片进行一定的压缩&#xff0c;而且并且尽量还原图片的清…

vue项目中scss文件导出,js文件引入scss文件时为空{}

解决办法一&#xff1a; 将scss文件重命名为 ‘原名.module.scss’ 解决办法二&#xff1a;降低vue脚手架的版本 "vue/cli-plugin-babel": "~4.5.0", "vue/cli-plugin-eslint": "~4.5.0", "vue/cli-service": "~4.5.0…

二十五、go语言的通道

目录 一、收发通信 二、将通道作为参数传递&#xff08;读、写、读写&#xff09; 三、select 1、先收到消息的先执行 2、一直没有收到消息退出通道 3、不知道何时退出情况下退出通道 go语言中的goroutine可以看成线程&#xff0c;但是又不能看成和其它语言一样的线程&am…

【Kubernetes知识点问答题】Namespace(命名空间)

目录 1. 什么是 K8s 的 namespace&#xff1f; 2. 系统默认创建了哪几个 namespace&#xff1f; 1. 什么是 K8s 的 namespace&#xff1f; 在 K8s 中&#xff0c; Namespace&#xff08;命名空间&#xff09;提供了一种机制&#xff0c;将同一集群中的资源划分为相互隔离的组…

c# net8调用vc写的dll

dll程序&#xff08;vc,x86) 头文件 extern "C" int __declspec(dllexport) WINAPI add(int a, int b);实现 int WINAPI add(int a, int b) {return a b; }c#/net8 函数声明&#xff1a; [DllImport("dll/Dll1.dll", CallingConvention CallingCo…

Git 提交代码注释信息规范

在团队协作开发过程中&#xff0c;规范的 Git 提交信息不仅能提高代码维护的效率&#xff0c;还能让其他开发者更容易理解每次提交的目的和内容。下面是常用的 Git 提交信息类型及其详细说明。此外&#xff0c;还包括一些额外的提交类型&#xff0c;以便更全面地覆盖开发过程中…