10 创建型模式-原型模式
引言:
创建对象的五种方式:
- 通过new关键字
- 通过Class类的newInstance()方法
- 通过Constructor类的newInstance()方法
- 利用Clone方法
- 反序列化
Clone方法:
其实现方式正是通过调用 Object 类的 clone() 方法来完成。
protected native Object clone() throws CloneNotSupportedException;
public class Person implements Cloneable{public String pname;public int page;public Address address;public Person() {}public Person(String pname,int page){this.pname = pname;this.page = page;this.address = new Address();}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}public void setAddress(String provices,String city ){address.setAddress(provices, city);}public void display(String name){System.out.println(name+":"+"pname=" + pname + ", page=" + page +","+ address);}public String getPname() {return pname;}public void setPname(String pname) {this.pname = pname;}public int getPage() {return page;}public void setPage(int page) {this.page = page;}}
public class Address {private String provices;private String city;public void setAddress(String provices,String city){this.provices = provices;this.city = city;}@Overridepublic String toString() {return "Address [provices=" + provices + ", city=" + city + "]";}}
这是一个我们要进行赋值的原始类 Person。下面我们产生一个 Person 对象,并调用其 clone 方法复制一个新的对象。
注意:调用对象的 clone 方法,必须要让类实现 Cloneable 接口,并且覆写 clone 方法。
测试:
@Test
public void testShallowClone() throws Exception{Person p1 = new Person("zhangsan",21);p1.setAddress("湖北省", "武汉市");Person p2 = (Person) p1.clone();System.out.println("p1:"+p1);System.out.println("p1.getPname:"+p1.getPname().hashCode());System.out.println("p2:"+p2);System.out.println("p2.getPname:"+p2.getPname().hashCode());p1.display("p1");p2.display("p2");p2.setAddress("湖北省", "荆州市");System.out.println("将复制之后的对象地址修改:");p1.display("p1");p2.display("p2");
}
深拷贝
如何实现深拷贝?
- 让每个引用类型属性内部都重写clone() 方法
- 利用序列化
1 原型模式介绍
定义: 原型模式(Prototype Design Pattern)用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
西游记中的孙悟空 拔毛变小猴,孙悟空这种根据自己的形状复制出多个身外化身的技巧,在面向对象软件设计领域被称为原型模式.孙悟空就是原型对象.
2 原型模式原理
3 深克隆与浅克隆
3) 浅克隆代码实现:
测试
@Test
public void test01() throws CloneNotSupportedException {ConcretePrototype c1 = new ConcretePrototype();ConcretePrototype c2 = c1.clone();//输出falseSystem.out.println("对象c1和c2是同一个对象?" + (c1==c2));
}
4) 深克隆代码实现
/*** 具体原型类* 实现Cloneable标识接口,表示当前类对象可复制**/
public class ConcretePrototype implements Cloneable, Serializable {private Person person;public Person getPerson() {return person;}public void setPerson(Person person) {this.person = person;}public void show(){System.out.println("嫌疑人姓名: " + person.getName());}public ConcretePrototype() {System.out.println("具体原型对象创建成功!");}@Overrideprotected ConcretePrototype clone() throws CloneNotSupportedException {System.out.println("克隆对象复制成功!");return (ConcretePrototype) super.clone();}
}
import java.io.Serializable;public class Person implements Serializable {private String name;public Person() {}public Person(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
//浅拷贝@Testpublic void test02() throws CloneNotSupportedException {ConcretePrototype c1 = new ConcretePrototype();Person p1 = new Person("峰哥");c1.setPerson(p1);//复制c1ConcretePrototype c2 = c1.clone();Person p2 = c2.getPerson();p2.setName("凡哥");c1.show();c2.show();//输出true,克隆对象和原型对象还是共享name属性的System.out.println("对象p1和对象p2是同一个对象吗?" + (p1 == p2));}
如果有需求场景中不允许共享同一对象,那么就需要使用深拷贝,如果想要进行深拷贝需要使用到对象序列化流 (对象序列化之后,再进行反序列化获取到的是不同对象).
4 原型模式应用实例
代码实现
广告模板代码
/*** 广告模板**/
public class AdvTemplate {//广告信名称private String advSubject = "xx银行本月还款达标,可抽iPhone 13等好礼!";//广告信内容private String advContext = "达标用户请在2022年3月1日到2022年3月30日参与抽奖......";public String getAdvSubject() {return advSubject;}public void setAdvSubject(String advSubject) {this.advSubject = advSubject;}public String getAdvContext() {return advContext;}public void setAdvContext(String advContext) {this.advContext = advContext;}
}
邮件类代码
/*** 邮件类**/
public class Mail {private String receiver; //收件人private String subject; //邮件名称private String appellation; //称呼private String context; //邮件内容private String tail; //邮件尾部 "xx版权所有"public Mail(AdvTemplate advTemplate) {this.subject = advTemplate.getAdvSubject();this.context = advTemplate.getAdvContext();}public String getReceiver() {return receiver;}public void setReceiver(String receiver) {this.receiver = receiver;}public String getSubject() {return subject;}public void setSubject(String subject) {this.subject = subject;}public String getAppellation() {return appellation;}public void setAppellation(String appellation) {this.appellation = appellation;}public String getContext() {return context;}public void setContext(String context) {this.context = context;}public String getTail() {return tail;}public void setTail(String tail) {this.tail = tail;}
}
客户类
/*** 业务场景**/
public class Client {//发送邮件的数量private static int MAX_COUNT = 6;//发送邮件public static void sendMail(Mail mail){System.out.println("标题: " + mail.getSubject() + "\t 收件人: " + mail.getReceiver()+ "\t ...发送成功!");}public static void main(String[] args) {int i = 0;//定义模板Mail mail = new Mail(new AdvTemplate());mail.setTail("xxx银行版权所有");while(i < MAX_COUNT){//每封邮件不同的信息mail.setAppellation(" 先生 (女士)");Random random = new Random();int num = random.nextInt(999999999);mail.setReceiver(num + "@"+"mashibing.com");//发送邮件sendMail(mail);i++;}}}
代码重构
Mail类
public class Mail implements Cloneable {private String receiver; //收件人private String subject; //邮件名称private String appellation; //称呼private String context; //邮件内容private String tail; //邮件尾部 "xx版权所有"public Mail(AdvTemplate advTemplate) {this.subject = advTemplate.getAdvSubject();this.context = advTemplate.getAdvContext();}public String getReceiver() {return receiver;}public void setReceiver(String receiver) {this.receiver = receiver;}public String getSubject() {return subject;}public void setSubject(String subject) {this.subject = subject;}public String getAppellation() {return appellation;}public void setAppellation(String appellation) {this.appellation = appellation;}public String getContext() {return context;}public void setContext(String context) {this.context = context;}public String getTail() {return tail;}public void setTail(String tail) {this.tail = tail;}@Overrideprotected Mail clone() {Mail mail = null;try {return (Mail)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();return null;}}
}
Client类
public class Client {//发送邮件的数量private static int MAX_COUNT = 6;//发送邮件public static void sendMail(Mail mail){System.out.println("标题: " + mail.getSubject() + "\t 收件人: " + mail.getReceiver()+ "\t ...发送成功!");}public static void main(String[] args) {int i = 0;//定义模板Mail mail = new Mail(new AdvTemplate());mail.setTail("xxx银行版权所有");while(i < MAX_COUNT){//每封邮件不同的信息Mail cloneMail = mail.clone();cloneMail.setAppellation(" 先生 (女士)");Random random = new Random();int num = random.nextInt(999999999);cloneMail.setReceiver(num + "@"+"mashibing.com");//发送邮件sendMail(cloneMail);i++;}}
}
5 原型模式总结
原型模式的优点:
原型模式缺点:
需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时需要修改源代码,违背了开闭原则.
使用场景
相关文章:

10 创建型模式-原型模式
引言: 创建对象的五种方式: 通过new关键字通过Class类的newInstance()方法通过Constructor类的newInstance()方法利用Clone方法反序列化 Clone方法: 其实现方式正是通过调用 Object 类的 clone() 方法来完成。 protected native Object cl…...

MSQL系列(七) Mysql实战-SQL语句Join,exists,in的区别
Mysql实战-SQL语句Join,exists,in的区别 前面我们讲解了索引的存储结构,BTree的索引结构,以及索引最左侧匹配原则及讲解一下常用的SQL语句的优化建议,今天我们来详细讲解一下 我们经常使用的 join, exist&…...

最新壁纸自动采集系统网站PHP源码/360壁纸官方数据接口采集/ZHEYI采集源码
源码介绍: 最新壁纸自动采集系统网站PHP源码,它是ZHEYI自动采集源码,能够在360壁纸官方数据接口采集。很好用的壁纸网站源码分享,仅供学习,请勿商用。 ZHEYI自动采集壁纸PHP源码,能全自动采集高清壁纸网源…...

Redis在分布式场景下的应用
分布式缓存 缓存的基本作用是在高并发场景下对应服务的保护缓冲 – 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题: redis由于高强度性能采用内存 但是意味着丢失的风险单结点redis并发能力有限分布式服务中数据过多 依赖内存的redis 明显单机不…...

2316. 统计无向图中无法互相到达点对数
2316. 统计无向图中无法互相到达点对数 难度: 中等 来源: 每日一题 2023.10.21 给你一个整数 n ,表示一张 无向图 中有 n 个节点,编号为 0 到 n - 1 。同时给你一个二维整数数组 edges ,其中 edges[i] [ai, bi] 表示节点 ai 和 bi 之间…...
Selenium定向爬取海量精美图片及搜索引擎杂谈
我自认为这是自己写过博客中一篇比较优秀的文章,同时也是在深夜凌晨2点满怀着激情和愉悦之心完成的。首先通过这篇文章,你能学到以下几点: 1.可以了解Python简单爬取图片的一些思路和方法 2.学习Selenium自动、测试分析动态网页和正则表达式的区别和共同点 …...

面试题—JAVA基础①
文章目录 1.Java面向对象有哪些特征?2.ArrayList和LinkedList有什么区别?3.Java接口和抽象类有哪些区别?4.hashcode和equals如何使用?5.try-catch6.局部变量和实例变量7.String、StringBuffer、StringBuilder 的区别?8…...
naive-ui的n-data-table标签奇特bug记录
具体参考之前的博文:vueday02——使用naive-ui做一个ACM看榜-CSDN博客 具体代码在这里面 原因:在本地运行的时候,datatable里面使用列表渲染成字符串前端设置样式进行转换,但是在正式部署的时候,这个组件没有将其自动…...

微信小程序OA会议系统个人中心授权登入
在我们的完成微信登入授权之前,首先我们要完成我们前面所写的代码,如果有不会的大家可以去看以下我发的前面几个文章链接我发下面了,各位加油! 微信小程序OA会议系统数据交互-CSDN博客 微信小程序会议OA系统其他页面-CSDN博客 …...

Git(一)Windows下安装及使用Git Bash
目录 一、简介1.1 什么是Git?1.2 Git 的主要特点1.3 什么是 Git Bash? 二、下载三、安装3.1 同意协议3.2 选择安装位置3.3 其他配置(【Next】 即可)3.4 安装完毕3.5 打开 Git Bash 官网地址: https://www.git-scm.com/…...

[AUTOSAR][诊断管理][ECU][$19] 读取ECU的DTC故障信息
一、简介 在车载诊断中常用的诊断协议有ISO 14229等,在协议中主要定义了诊断请求、诊断响应的报文格式及ECU该如何处理诊断请求的应用。其中ISO 14229系列标准协议定义了用于行业内诊断通信的需求规范,也就是UDS。UDS主要应用于OSI七层模型的第七层——…...
前端精度问题 (id 返回的和传给后端的不一致问题)
eg: 后端返回 id 10976458979374929 前端获取到的: 10976458979374928 原因: js 中 Number类型范围-2^53 1 到 2^53 - 1 Number.isSafeInteger()用来判断一个整数是否落在这个范围之内。 java中 Long 类型的取值范围是-2^63 1 到 2^63 - 1, 比JavaScript中大很多࿰…...

WPF Material Design UI框架
前言 Material Design in xaml 是开源免费的ui框架,工控软件主打的就是简单界面。 以下简称MD 相关资源 MaterialDesignInXamlToolkit Github 地址 MD 快速启动 MD 案例压缩包 MD 框架使用 启动环境配置 安装Nuget包 App.xaml 配置 <Application x:Class&qu…...

C语言求 3*3 矩阵对角线之和
完整代码: // 求 3*3 矩阵对角线之和 #include<stdio.h>int main() {int n3;int arr[3][3];// 输入矩阵printf("请输入矩阵的元素:\n");for (int i 0; i < n; i){for (int j 0; j < n; j){scanf("%d", &arr[i][j]);}}int su…...

缓存分片中的哈希算法与一致性哈希算法
什么是缓存分片 在高并发场景下,缓存往往成为了瓶颈。这时候,我们可以通过缓存数据分片的方式来解决问题。所谓缓存数据分片,就是将缓存数据按照一定的规则分成多个片段,每个片段由不同的缓存节点负责。这样做有两个好处…...

线框图软件:Balsamiq Wireframes mac中文介绍
Balsamiq Wireframes mac是一款用于创建线框图的软件工具。它旨在帮助用户快速制作出清晰、简洁的界面原型,以便在设计和开发过程中进行协作和沟通。 Balsamiq Wireframes具有简单直观的用户界面,使用户能够快速添加和编辑各种用户界面元素,如…...

【wxWidgets实现透明wxPanel_核心实现_原创思想】
描述 wxWidgets 根本就没有实现过透明wxPanel容器,你设置wxTRANSPARENT_WINDOW,结果sorry 黑色,哈哈哈哈, 就是和你作对.想想当下那么漂亮的桌面, 背景, 透明, 特效.哎 悲哀啊,实现不了,就那死板的界面特性. 网上找了好久,也是乱七八糟,改底层代码还是算了吧,升级特要命.都是只…...

重大技术问题,iPhone 15 Pro Max面临“烧屏门”风波 | 百能云芯
近期,社交媒体平台上陆续涌现大量用户和数码博主就iPhone 15 Pro Max出现烧屏问题的投诉与评论。 烧屏问题是OLED屏幕常见的一个缺陷,这是由OLED屏幕发光机制引发的,OLED屏幕可视为由无数微小的灯泡-像素点构成,这些像素点可以独立…...

深度学习中的不确定性综述
领域学者: http://www.gatsby.ucl.ac.uk/~balaji/ 论文标题: A Survey of Uncertainty in Deep Neural Networks 论文链接: https://arxiv.org/pdf/2107.03342.pdf 概要 在过去的十年中,神经网络几乎遍及所有科学领域&#x…...

uni-app 小宠物 - 会说话的小鸟
在 template 中 <view class"container"><view class"external-shape"><view class"face-box"><view class"eye-box eye-left"><view class"eyeball-box eyeball-left"><span class"…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...