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

原型模式(创建型)

一、前言

        原型模式是一种创建型设计模式,它允许在运行时通过克隆现有对象来创建新对象,而不是通过常规的构造函数创建。在原型模式中,一个原型对象可以克隆自身来创建新的对象,这个过程可以通过深度克隆或浅克隆来实现。简单说原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。

        原型模式包含三个角色:

        ①Prototype(抽象原型类):定义用于克隆自身的接口,通常是一个抽象类或接口,其中声明了一个克隆方法 clone(),用于创建一个新的对象,具体的克隆操作由子类实现。

        ②ConcretePrototype(具体原型类):实现 Prototype 接口,实现 clone() 方法,完成对象的克隆操作。每个具体原型类都有自己的一些属性和方法,不同的具体原型类之间具有不同的实现方式。

        ③Client(客户类):使用原型模式创建新的对象,在原型模式中,客户端通过克隆接口来创建新的对象,而不是通过实例化的方式。客户端需要获取一个原型对象,并通过克隆方法来创建新的对象,从而避免了创建新对象的开销。

        原型模式的克隆分为浅拷贝和深拷贝两种。

二、浅拷贝

        创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

        这里抽象原型类不用自己创建,都是Object,里面有clone()方法:

        具体原型类实现Cloneable,里面重写clone方法,直接super调用父类的clone方法即可:

import java.util.List;/*** @Author dengyifan* @create 2023/11/10 10:19* @description*/
public class UserPrototype implements Cloneable{private String name;private Integer age;private List<String> messages;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public List<String> getMessages() {return messages;}public void setMessages(List<String> messages) {this.messages = messages;}@Overrideprotected UserPrototype clone() throws CloneNotSupportedException {return (UserPrototype) super.clone();}
}

        客户类:

import java.util.ArrayList;
import java.util.List;/*** @Author dengyifan* @create 2023/11/10 10:22* @description*/
public class PrototypeClient {public static void main(String[] args) throws CloneNotSupportedException {UserPrototype userPrototype1 = new UserPrototype();userPrototype1.setName("tom");userPrototype1.setAge(18);List<String> messages1 = new ArrayList<>();messages1.add("test");userPrototype1.setMessages(messages1);UserPrototype userPrototype2 = userPrototype1.clone();System.err.println(String.format("两个对象是否一致:%s", userPrototype1 == userPrototype2));System.err.println(String.format("两个对象的name属性是否一致:%s", userPrototype1.getName() == userPrototype2.getName()));System.err.println(String.format("两个对象的messages属性是否一致:%s", userPrototype1.getMessages() == userPrototype2.getMessages()));System.err.println(userPrototype1.getMessages());System.err.println(userPrototype2.getMessages());messages1.clear();messages1.add("test1");System.err.println(userPrototype1.getMessages());System.err.println(userPrototype2.getMessages());}
}

        运行结果:

        通过结果可以看到,通过克隆的对象与原型对象的引用不一致,说明再内存中存在两个不同的对象,一个是原型对象,一个是克隆生成的对象。而这里属性都显示是一致的,结果都是true,说明两个对象的成员对象是同一个,也就是对象本身是复制了,但是其成员的对象再内存中没有复制。并且我们修改原型的messages属性,克隆对象的messages也跟着改变,说明属性确实是同一个对象的引用。

三、深拷贝

        深拷贝中除了原型对象与克隆生成的对象被复制以外,里面的属性也需要被复制,即地址都不一样。这里深拷贝实现了Serializable,即进行了序列化。

import java.io.*;
import java.util.List;/*** @Author dengyifan* @create 2023/11/10 15:43* @description*/
public class UserPrototypeDeep implements Serializable {private String name;private Integer age;private List<String> messages;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public List<String> getMessages() {return messages;}public void setMessages(List<String> messages) {this.messages = messages;}protected UserPrototypeDeep deepClone() throws Exception{ByteArrayOutputStream bao=new ByteArrayOutputStream();ObjectOutputStream oos=new ObjectOutputStream(bao);oos.writeObject(this);//将对象从流中取出ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());ObjectInputStream ois=new ObjectInputStream(bis);return (UserPrototypeDeep) ois.readObject();}
}
import java.util.ArrayList;
import java.util.List;/*** @Author dengyifan* @create 2023/11/10 15:46* @description*/
public class PrototypeDeepClient {public static void main(String[] args) throws Exception {UserPrototypeDeep userPrototypeDeep1 = new UserPrototypeDeep();userPrototypeDeep1.setAge(19);userPrototypeDeep1.setName("tom");List<String> messages1 = new ArrayList<>();messages1.add("test");userPrototypeDeep1.setMessages(messages1);UserPrototypeDeep userPrototypeDeep2 = userPrototypeDeep1.deepClone();System.err.println(String.format("两个对象是否一致:%s", userPrototypeDeep1 == userPrototypeDeep2));System.err.println(String.format("两个对象的name属性是否一致:%s", userPrototypeDeep1.getName() == userPrototypeDeep2.getName()));System.err.println(String.format("两个对象的messages属性是否一致:%s", userPrototypeDeep1.getMessages() == userPrototypeDeep2.getMessages()));System.err.println(userPrototypeDeep1.getMessages());System.err.println(userPrototypeDeep2.getMessages());messages1.clear();messages1.add("test1");System.err.println(userPrototypeDeep1.getMessages());System.err.println(userPrototypeDeep2.getMessages());}
}

        运行结果:

        可以看出除了对象本身不一致以外,里面的属性也不一致,当修改原型对象里面引用对象的属性时,克隆对象的属性不会发生变化,即也证明属性不是同一个对象。

        对于原型模式的应用场景,主要有以下几点:

1. 当对象的创建过程非常复杂或耗费大量资源时,可以使用原型模式来复制一个现有对象,从而避免重复创建对象。

2. 当需要创建多个相似的对象时,可以使用原型模式来减少重复代码,提高代码的重用性。

3. 当创建对象的过程需要大量的数据准备或配置时,可以使用原型模式来复制一个已经配置好的对象,从而避免重复的数据准备或配置过程。

4. 当需要动态生成对象的子类时,可以使用原型模式来复制一个已有的对象,并对其进行修改,从而避免重新编写子类的代码。

5. 当需要保护对象的状态时,可以使用原型模式来创建对象的副本,并将副本交给其他对象使用,从而避免原始对象的状态被修改。

相关文章:

原型模式(创建型)

一、前言 原型模式是一种创建型设计模式&#xff0c;它允许在运行时通过克隆现有对象来创建新对象&#xff0c;而不是通过常规的构造函数创建。在原型模式中&#xff0c;一个原型对象可以克隆自身来创建新的对象&#xff0c;这个过程可以通过深度克隆或浅克隆来实现。简单说原型…...

Linux命令(118)之paste

linux命令之paste 1.paste介绍 linux命令paste命令是把每个文件以列对列的方式&#xff0c;一列列地加以合并 2.paste用法 paste [参数] filename... paste参数 参数说明-d使用指定的分隔符进行合并-s以行来指定文件 3.实例 3.1.使用冒号(:)合并文件 命令&#xff1a; …...

使用零拷贝技术实现消息转发功能

零拷贝技术介绍&#xff1a;史上最全零拷贝总结-CSDN博客 这是一个简单的基于epoll的Linux TCP代理程序&#xff0c;通过匿名管道和零拷贝技术的splice函数&#xff0c;将两个TCP端口相互连接&#xff0c;并转发数据。 #define _GNU_SOURCE 1 #include <sys/socket.h> …...

【编程语言发展史】SQL的发展历史

目录 目录 SQL概述 SQL发展历史 SQL特点 SQL基本语句 SQL是结构化查询语言(Structure Query Language)的缩写&#xff0c;它是使用关系模型的数据库应用语言&#xff0c;由IBM在70年代开发出来&#xff0c;作为IBM关系数据库原型System R的原型关系语言&#xff0c;实现了…...

2023NOIP A层联测28-小猫吃火龙果

给你一个长为 n n n 的序列&#xff0c;每个位置是 A , B , C A,B,C A,B,C 三个中的一个物品。 A A A 吃 B B B&#xff0c; B B B 吃 C C C&#xff0c; C C C 吃 A A A。 现在有 m m m 次操作&#xff0c;每次操作有两种&#xff1a; 区间修改&#xff1a;给出 l , r…...

C# Dictionary与List的用法区别与联系

C#是一门广泛应用于软件开发的编程语言&#xff0c;其中Dictionary和List是两种常用的集合类型。它们在存储和操作数据时有着不同的特点和用途。本文将详细探讨C# Dictionary和List的用法区别与联系&#xff0c;并通过代码示例进行对比&#xff0c;以帮助读者更好地选择适合自己…...

Git应用(1)

一、Git Git(读音为/gɪt/。中文 饭桶 )是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。 了解更多可到GIT官网&#xff1a;Git - Downloads GIT一般工作流程如下&#xff1a; 1&#xff0e;从远程仓库中克隆 Git 资源作为本地…...

【Java】Netty创建网络服务端客户端(TCP/UDP)

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Netty创建网络服务端客户端示例。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更…...

Android 设计模式--单例模式

一&#xff0c;定义 单例模式就是确保某一个类只有一个实例&#xff0c;而且自行实例化&#xff0c;并向整个系统提供这个实例 二&#xff0c;使用场景 确保某个类只有一个对象的使用场景&#xff0c;避免产生多个对象消耗过多的资源&#xff0c;或者某种类型的对象只应该有…...

语音识别与自然语言处理(NLP):技术前沿与未来趋势

语音识别与自然语言处理&#xff08;NLP&#xff09;&#xff1a;技术前沿与未来趋势 随着科技的快速发展&#xff0c;语音识别与自然语言处理&#xff08;NLP&#xff09;技术逐渐成为人工智能领域的研究热点。这两项技术的结合&#xff0c;使得机器能够更好地理解和处理人类语…...

k8s-docker二进制(1.28)的搭建

二进制文件-docker方式 1、准备的服务器 角色ip组件k8s-master1192.168.11.111kube-apiserver,kube-controller-manager,kube-scheduler,etcdk8s-master2192.168.11.112kube-apiserver,kube-controller-manager,kube-scheduler,etcdk8s-node1192.168.11.113kubelet,kube-prox…...

【代码随想录】算法训练计划18

1、513. 找树左下角的值 题目&#xff1a; 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 思路&#xff1a; 递归&#xff0c;规则&#xff0c;基本可以自己写出来 var maxDepth int var res int fun…...

Leetcode刷题详解—— 组合总和

1. 题目链接&#xff1a;39. 组合总和 2. 题目描述&#xff1a; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些…...

Echarts柱状体实现滚动条动态滚动

当我们柱状图中X轴数据太多的时候&#xff0c;会自动把柱形的宽度挤的很细&#xff0c;带来的交互非常不好&#xff0c;因此就有一个属性来解决&#xff1a;dataZoom 第一种简易的版本&#xff0c;横向滚动。 dataZoom: {show: true, // 为true 滚动条出现realtime: true, // 实…...

SplayTree高分测试用例

测试用例结果展示 覆盖率 变异得分 测试注意点 从SplayTree测起&#xff0c;然后再测SubSplayTree&#xff0c;因为前者调用后者。SplaySubTree的remove方法大部分内容需要通过反射才能测到。value和index在SplayTree当中都不是唯一的。一个index可能对应多个value。 不足之…...

制作麒麟V10-server-sp2镜像

1.挂载iso 文件到目录 mount -o loop /xxx.iso /mnt 这样mnt 目录下会有iso 解压相关的文件 2.修改源文件内容 vim /etc/yum.repos.d/ kylin_x86_64.repo 将里面的所有的源enabled 都改成 0 并添加一个新的源 [ks10-local] name Kylin Linux Advanced Server 10 - Local base…...

2.docker镜像的导入导出

目录 概述docker 常用命令下载导出导入镜像结束 概述 docker 常用命令 本章节使用到的命令&#xff0c;总结在此&#xff0c;后面有使用案例。 命令作用docker images显示镜像docker rmi $(docker images -q)删除系统上所有的镜像docker rmi -f强制删除多个镜像 &#xff1a…...

bs4介绍和遍历文档树、搜索文档树、案例:爬美女图片、 bs4其它用法、css选择器

bs4介绍和遍历文档树 BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库&#xff0c;解析库 需要安装模块&#xff1a;pip install beautifulsoup4 使用 解析库可以使用 lxml&#xff0c;速度快&#xff08;必须安装&#xff09; 可以使用python内置的 # html…...

微服务-开篇-个人对微服务的理解

从吃饭说起 个人理解新事物的时候喜欢将天上飞的理念转换成平常生活中的实践&#xff0c;对比理解这些高大上的名词&#xff0c;才能让我们减少恐慌的同时加深理解。废话不多说&#xff0c;我们从吃饭开始说起&#xff0c;逐渐类比出微服务的思想。 &#xff08;个人见解&…...

机器学习算法-集成学习

概念 集成学习是一种机器学习方法&#xff0c;它通过构建并结合多个机器学习器&#xff08;基学习器&#xff09;来完成学习任务。集成学习的潜在思想是即便某一个弱分类器得到了错误的预测&#xff0c;其他的弱分类器也可以将错误纠正回来。集成学习通常被视为一种元算法&…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...