设计模式——原型模式

news2024/12/23 22:25:34
  1. 原型模式比较简单,本质就是将一个设置好一部分公共属性的对象进行克隆,产生出大量的对象,再对每个对象进行相应的个性化处理
  2. 需要注意的是:对象克隆时,如果其成员变量中存在引用类型(数组、引用对象等),就必须解决浅拷贝问题
  3. 浅拷贝:对于被克隆对象的成员变量,如果是基本类型(包括String),则会直接克隆,但对于引用类型,则是引用被克隆对象的地址,也就是说克隆对象可以直接操作原对象的引用类型成员变量
  4. 深拷贝:对象进行克隆时,将引用类型的成员变量也进行拷贝(该对象也需要实现Cloneable接口,否则不能拷贝),然后再赋值给克隆对象

原型模式(基本案例)

邮件类(个性属性多)

/**
 * 邮件
 */
public class Mail implements Cloneable{
	// 收件人
	private String receiver;
	// 邮件名称
	private String subject;
	// 称谓
	private String appellation;
	// 邮件内容
	private String content;
	// 邮件尾部
	private String tail;

	public Mail(AdvTemplate advTemplate){
		this.content = advTemplate.getAdvContent();
		this.subject = advTemplate.getAdvSubject();
	}

	@Override
	public Mail clone(){
		Mail mail = null;
		try {
			mail = (Mail) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return mail;
	}
	// Getter、Setter省略
}

模板类(公共属性多)

/**
 * 广告信模板代码
 */
public class AdvTemplate {
	// 广告信名称
	private String advSubject = "XX银行国庆信用卡抽奖活动";
	// 广告信内容
	private String advContent = "国庆抽奖活动通知:只要刷卡就送100元话费充值券!";

	public String getAdvSubject() {
		return advSubject;
	}

	public String getAdvContent() {
		return advContent;
	}
}

入口类

public class PrototypeMain {
	// 发送账单的数量,假定6
	private static final int MAX_COUNT = 6;

	public static void main(String[] args) {
		// 模拟发送邮件
		int i = 0;
		Mail mail = new Mail(new AdvTemplate());
		mail.setTail("XX银行版权所有");
		while (i < MAX_COUNT) {
			// 改动:通过克隆,而不是new的方式创建对象,该对象保留大部分细节,个性部分再修改即可
			Mail cloneMail = mail.clone();
			cloneMail.setAppellation(getRandString(5) + "先生(女士)");
			cloneMail.setReceiver(getRandString(5) + "@" + getRandString(8) + ".com");
			// 然后发送邮件
			sendMain(cloneMail);
			i++;
		}
	}

	private static void sendMain(Mail mail) {
		System.out.println("标题:" + mail.getSubject() + "\t收件人:" + mail.getReceiver() + "\t...发送成功");
	}

	private static String getRandString(int maxLength) {
		String source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
		StringBuffer sb = new StringBuffer();
		Random rand = new Random();
		for (int i = 0; i < maxLength; i++) {
			sb.append(source.charAt(rand.nextInt(source.length())));
		}
		return sb.toString();
	}
}

结果

在这里插入图片描述

浅拷贝、深拷贝案例

/**
 * 浅拷贝
 * 1. 浅拷贝对对象中基础类型的成员变量(包括String)是直接拷贝的
 * 2. 但是对于引用类型(数组、对象)的变量则不拷贝,而是采用地址引用,这样就会造成克隆对象可以操作原对象中的成员变量(对象类型)
 * 3. 注意:引用类型的成员变量也必须实现Cloneable接口,否则就会编译报错
 * 例如:List<String> list = new ArrayList<>()就会报错,ArrayList<String> list = new ArrayList<>() 才不会报错
 */
class ShallowCopyThing implements Cloneable{
	private ArrayList<String> list = new ArrayList<>();

	@Override
	public ShallowCopyThing clone(){
		ShallowCopyThing thing = null;
		try {
			// 这步只能算作浅拷贝,浅拷贝对于`引用类型`成员变量是地址引用,克隆的对象也能操作原对象的成员变量
			thing = (ShallowCopyThing) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return thing;
	}
	// 设置List的值
	public void setValue(String value){
		this.list.add(value);
	}
	// 获取List的值
	public ArrayList<String> getValue(){
		return this.list;
	}
}

/**
 * 深拷贝
 * 连同类中的成员变量一起拷贝
 */
class DeepCopyThing implements Cloneable{
	private ArrayList<String> list = new ArrayList<>();
	private Person per = new Person();

	@Override
	public DeepCopyThing clone(){
		DeepCopyThing thing = null;
		try {
			// 这步只能算作浅拷贝,浅拷贝对于`引用类型`成员变量是地址引用,克隆的对象也能操作原对象的成员变量
			thing = (DeepCopyThing) super.clone();
			// 这步才算是深拷贝,对私有成员变量独立拷贝,再赋值给克隆对象
			thing.list = (ArrayList<String>) this.list.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return thing;
	}
	// 设置List的值
	public void setValue(String value){
		this.list.add(value);
	}
	// 获取List的值
	public ArrayList<String> getValue(){
		return this.list;
	}
}

public class ShallowAndDeepCopyMain {
	public static void main(String[] args) {
		shallowCopy();
		deepCopy();
	}
	public static void deepCopy(){
	    DeepCopyThing thing = new DeepCopyThing();
	    thing.setValue("Good");
	    DeepCopyThing clone = thing.clone();
	    clone.setValue("Boy");
	    System.out.println("deepCopy: " + thing.getValue());
		}
	public static void shallowCopy(){
		ShallowCopyThing thing = new ShallowCopyThing();
		thing.setValue("Good");
		ShallowCopyThing clone = thing.clone();
		clone.setValue("Boy");
		System.out.println("shallowCopy: " + thing.getValue());  // 结果是原对象的值会被拷贝的值操作,极不安全
	}
}

结果

在这里插入图片描述

参考书籍

秦小波《设计模式之禅》

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

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

相关文章

《人工智能.一种现代方法》原版精读思维导图-第二章

目录 书籍 相关 2. Intelligent Agents 2.1 Agents and Environments 2.2 Good Behavior: The Concept of Rationality 2.3 The Nature of Environments 2.4 The Structure of Agents summary 书籍 人工智能.一种现代方法 Artificial Intelligence. The Modern Appro…

基于LLM大模型开发Web App生成器

随着越来越多的代码生成模型公开可用&#xff0c;现在可以以我们以前无法想象的方式进行文本到网络甚至文本到应用程序。 本教程介绍了一种通过流式传输和渲染内容来生成 AI Web 内容的直接方法。 推荐&#xff1a;用 NSDT设计器 快速搭建可编程3D场景。 1、在 Node 应用程序中…

13 个最佳免费 PDF 编辑器清单

您正在寻找一款真正免费的 PDF 编辑器&#xff0c;不仅可以编辑和添加文本&#xff0c;还可以更改图像、添加您自己的图形、签署您的名字、填写表格等等&#xff1f;您来对地方了&#xff1a;我研究了这些类型的应用程序&#xff0c;以得出您正在寻找的内容的列表。 其中一些是…

element 表格套输入框

实现效果&#xff1a; 编辑&#xff1a; 查看&#xff1a;点击平台补贴展示弹窗 <el-table:data"tableData"border:header-cell-style"{background:#D7D7D7,color:#000}"style"width: 100%"row-dblclick"dbclick":cell-class-name…

c++中的时间处理(3)与sleep相关的时间函数

1、Sleep()函数 头文件&#xff1a; Windows下为&#xff1a;windows.h Linux下为&#xff1a;unistd.h 注意&#xff1a; &#xff08;1&#xff09;Sleep是区分大小写的&#xff0c;有的编译器是大写&#xff0c;有的是小写。 &#xff08;2&#xff09;Sleep括号里的时间&…

ELK中grok插件、mutate插件、multiline插件、date插件的相关配置

目录 grok 正则捕获插件 自定义表达式调用 mutate 数据修改插件 示例&#xff1a; ●将字段old_field重命名为new_field ●添加字段 ●将字段删除 ●将filedName1字段数据类型转换成string类型&#xff0c;filedName2字段数据类型转换成float类型 ●将filedName字段中…

Nginx调优和探活配置

Nginx基本参数优化 1 . worker_processes 1; # 指定 Nginx 要开启的进程数&#xff0c;结尾的数字就是进程的个数&#xff0c;可以为 auto。 这个参数调整的是 Nginx 服务的 worker 进程数&#xff0c;Nginx 有 Master 进程和 worker 进程之分&#xff0c;Master 为管理进程、真…

Web常见请求参数接收的总结

首先本文所展示的参数接收的总结&#xff0c;都是基于Spring Boot框架而言的&#xff0c;不是一般传统方式使用request对象来完成参数的接收 简单参数的接收 对于简单参数的接收&#xff0c;在Spring Boot框架中&#xff0c;在Controller类中设置对应的处理方式时&#xff0c;…

SpringMVC 中的数据验证如何使用 @Valid 注解

SpringMVC 中的数据验证如何使用 Valid 注解 在 Web 开发中&#xff0c;数据验证是一个非常重要的环节。它可以确保数据的合法性和正确性&#xff0c;保护系统不受到恶意攻击或用户误操作的影响。在 SpringMVC 中&#xff0c;我们可以使用 Valid 注解来实现数据验证。 Valid 注…

排序算法第二辑——选择排序

一&#xff0c;选择排序 选择排序算是简单排序中的渣渣&#xff0c;这种算法基本上是没有什么用处的。但是作为一个初学者&#xff0c;我又必须要会写这种算法。这种算法的实现实现思想和它的名字一样&#xff0c;就是在一个范围内选择最大或者最小的数据然后再交换数据实现排序…

山西电力市场日前价格预测【2023-07-13】

日前价格预测 预测明日&#xff08;2023-07-13&#xff09;山西电力市场全天平均日前电价为342.42元/MWh。其中&#xff0c;最高日前电价为403.93元/MWh&#xff0c;预计出现在00: 15。最低日前电价为282.08元/MWh&#xff0c;预计出现在24: 00。 价差方向预测 1&#xff1a;实…

为什么大部分游戏公司仍在坚持使用SVN?

游戏开发是一个复杂的过程&#xff0c;涉及多个开发人员的协作和大量的代码、艺术资源以及其他项目文件。版本控制系统在游戏开发中起着至关重要的作用。它提供了对项目代码和文件的管理、跟踪和协作能力&#xff0c;对于保持项目的稳定性、团队协作的顺畅性以及追踪项目历史和…

《微服务架构设计模式》第七章 在微服务架构中实现查询

内容总结自《微服务架构设计模式》 在微服务架构中实现查询 一、使用API组合模式查询1、简介2、设计形式3、弊端 二、使用CQRS进行查询1、简介2、利弊 三、CQRS架构1、设计2、存储3、数据访问模块 四、总结 一、使用API组合模式查询 1、简介 这是最简单的方法&#xff0c;应尽…

WebDAV之π-Disk派盘 + PDF Expert

PDF Expert 支持WebDAV方式连接π-Disk派盘。 PDF Expert是一款macOS上的办公软件,它具有专业的PDF编辑功能,可以快速从邮件、网页支持PDF打开,支持用户进行阅读、批注等功能,用户可以直接在PDF上进行编辑文字图片,表单文档、创建笔记、添加书单等自定义使用,大大提高工…

手写JAVA线程池

前言 手写一个简单的java线程池&#xff1a;重点关注&#xff0c;如何确保一直有运行的线程&#xff1f;如何确保线程消费提交的任务信息&#xff1f;。一直保存有运行的线程底层使用的是死循环。使用消息队列确保信息的提交和消费。消息队列使用先进先出原则。 步骤 线程池…

漏洞复现 || OpenSNS远程命令执行漏洞

免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络应当遵守宪法法律&#xff0c;遵守公共秩序&#xff0c;尊重社会公德&#xff0c;不得危害网络安全&#xff0c;不得利用网络从事危害国家安全、荣誉和利益&#xff0c;未经授权请勿利用文章中的技术资料对任何计…

力扣 | 二分查找模板

力扣&#xff1a;二分查找 文章目录 &#x1f4da;二分查找&#x1f4da;模板I&#x1f449;x 的平方根&#x1f449;猜数字大小&#x1f449;搜索旋转排序数组 &#x1f4da;模板II&#x1f449;第一个错误的版本&#x1f449;寻找峰值 &#x1f4da;模板III&#x1f449;在排…

photoshop制作法线和凹凸贴图

做个选区 Ctrlj 法线贴图 生成凹凸贴图

Vue实现多语言(i18n)

第一步 安装i18n插件。 npm install vue-i18n第二步 在src目录下&#xff0c;创建一个【language】文件夹&#xff0c;并创建两个语言包js文件。 中文语言包&#xff1a;【zh.js】 英文语言包&#xff1a;【en.js】 第三步 完善en.js文件和zh.js文件。两个文件的结构要相…

系统架构设计师-项目管理

目录 一、盈亏平衡分析 二、进度管理 1、WBS工作分解结构 2、进度管理流程 &#xff08;1&#xff09;活动定义 &#xff08;2&#xff09;活动排序 &#xff08;3&#xff09;活动资源估算&#xff1a; &#xff08;4&#xff09;活动历时估算&#xff1a; &#xff08;5&…