手撕设计模式——克隆对象之原型模式

1.业务需求

​ 大家好,我是菠菜啊,前俩天有点忙,今天继续更新了。今天给大家介绍克隆对象——原型模式。老规矩,在介绍这期之前,我们先来看看这样的需求:《西游记》中每次孙悟空拔出一撮猴毛吹一下,变出一大批猴子加入战斗,他到底是怎么变的?如果我们帮他实现这个功能,代码怎么设计?

在这里插入图片描述

2.代码实现

首先先说第一个问题,怎么变的我也不知道。

在这里插入图片描述

但是第二个问题,可以尝试一下。

实现初步思路:

​ 我们新建一个猴子类,并且实例化多个猴子对象不就行了,太简单了。

Monkey类:

//猴子
public class Monkey {private String name;private String sex;private int age;private Weapon weapon;public Monkey(String name, String sex, int age, Weapon weapon) {this.name = name;this.sex = sex;this.age = age;this.weapon = weapon;}public Weapon getWeapon() {return weapon;}public void setWeapon(Weapon weapon) {this.weapon = weapon;}@Overridepublic String toString() {return "Monkey{" +"name='" + name + '\'' +", sex='" + sex + '\'' +", age=" + age +", weapon=" + weapon +'}';}
}

Weapon类:

//武器
public class Weapon {private String name;private String color;public Weapon(String name, String color) {this.name = name;this.color = color;}@Overridepublic String toString() {return "Weapon{" +"name='" + name + '\'' +", color='" + color + '\'' +'}';}
}

Client类:

public class Client {public static void main(String[] args) {Weapon weapon=new Weapon("金箍棒","金色");Monkey monkey=new Monkey("孙悟空","公",20,weapon);Weapon weapon2=new Weapon(monkey.getWeapon().getName(),monkey.getWeapon().getColor());Monkey monkey2=new Monkey("猴小弟",monkey.getSex(),monkey.getAge(),weapon2);Weapon weapon3=new Weapon(monkey.getWeapon().getName(),monkey.getWeapon().getColor());Monkey monkey3=new Monkey("猴小小弟",monkey.getSex(),monkey.getAge(),weapon3);System.out.println(monkey);System.out.println(monkey2);System.out.println(monkey3);}
}

思考:上述代码比较简单,功能是实现了,但是在克隆猴哥的时候,我们要将新建一个相同类的对象。 然后, 我还要必须遍历原始对象的所有成员变量, 并将成员变量值复制到新对象中。这也太麻烦了,如果属性是上千上万个,那么猴哥还没变出猴子,师傅就被妖怪给吃了。 而且并非所有对象都能通过这种方式进行复制, 因为有些对象可能拥有私有成员变量, 它们在对象本身以外是不可见的。而且克隆对象,要知道该对象类的所有依赖类才行,这样设计也太不符合迪米特法则了(详细见***《设计模式——设计原则介绍》***一文)。

3.方案改进

​ Java中提供了一个Cloneable接口,其中有一个clone()方法,我们只要实现这个方法就行了。

实现代码结构图

在这里插入图片描述

Monkey接口:

//猴子
public class Monkey implements Cloneable{//......@Overrideprotected Monkey clone() throws CloneNotSupportedException {return (Monkey)super.clone();}}

Client类:

public class Client {public static void main(String[] args) throws CloneNotSupportedException {Weapon weapon=new Weapon("金箍棒","金色");Monkey monkey=new Monkey("孙悟空","公",20,weapon);/* Weapon weapon2=new Weapon(monkey.getWeapon().getName(),monkey.getWeapon().getColor());Monkey monkey2=new Monkey("猴小弟",monkey.getSex(),monkey.getAge(),weapon2);Weapon weapon3=new Weapon(monkey.getWeapon().getName(),monkey.getWeapon().getColor());Monkey monkey3=new Monkey("猴小小弟",monkey.getSex(),monkey.getAge(),weapon3);*/Monkey monkey2=monkey.clone();monkey2.setName("猴小弟");Monkey monkey3=monkey.clone();monkey3.setName("猴小小弟");System.out.println(monkey);System.out.println(monkey2);System.out.println(monkey3);}
}

思考:这样我们就可以快速克隆对象,并且不需要知道对象创建的细节,又大大提高了性能,我们把这种设计模式叫做原型模式(Prototype )。上述代码还是有问题,可以继续往下看。

拓展:浅克隆和深克隆

​ 我们把上述代码稍微修改一下,看的就明显了。

Client修改后:

public class Client {public static void main(String[] args) throws CloneNotSupportedException {Weapon weapon=new Weapon("金箍棒","金色");Monkey monkey=new Monkey("孙悟空","公",20,weapon);Monkey monkey2=monkey.clone();monkey2.setName("猴小弟");Monkey monkey3=monkey.clone();monkey3.setName("猴小小弟");System.out.println("修改武器前:"+monkey);System.out.println("修改武器前:"+monkey2);System.out.println("修改武器前:"+monkey3);//修改各自的武器装备monkey.getWeapon().setColor("红色");monkey2.getWeapon().setColor("白色");monkey3.getWeapon().setColor("绿色");System.out.println("++++++修改武器+++++");System.out.println("修改武器后:"+monkey);System.out.println("修改武器后:"+monkey2);System.out.println("修改武器后:"+monkey3);}
}

**预期结果:**猴子们的武器颜色分别是红白绿。

实际结果:猴子们的武器都被绿了(一不小心开车了)。

在这里插入图片描述

排查原因发现,super.clone(),如果字段是值类型的,就复制值,如果字段是引用类型的,复制引用而不复制引用的对象(String是特殊的引用对象),因此猴子们引用的武器对象是一个。被复制的对象的所有变量值都含有原来对象相同的值,但是其它对象的引用仍然执行原来的对象,叫做浅克隆**。反之,把引用对象的变量指向复制过的新对象,这种叫做深克隆

我们如果要完成深复制,只需做如下修改:

Weapon类:

//武器
public class Weapon implements Cloneable{//...@Overrideprotected Weapon clone() throws CloneNotSupportedException {return (Weapon)super.clone();}}

Monkey类:

public class Monkey implements Cloneable{//...@Overrideprotected Monkey clone() throws CloneNotSupportedException {Monkey clone= (Monkey)super.clone();clone.weapon=this.weapon.clone();return clone;}}

**思考:**如果要深克隆,必须重写clone方法,如果克隆对象依赖对象的层级嵌套一多,代码较复杂。

4.定义和组成结构

原型模式(Prototype)从一个对象创建一个可定制的对象,而不需要知道任何创建细节。

​ 原型模式包含以下主要角色。

  • 抽象原型类(Prototype):规定了具体原型对象必须实现的接口。
  • 具体原型类(ConcretePrototype):实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • 访问类(Acess):使用具体原型类中的 clone() 方法来复制新的对象。

在这里插入图片描述

5.优缺点以及应用场景

优点:

  • 通过克隆一个已有的对象,简化对象的创建过程,不用关注对象的内部创建细节,符合迪米特法则
  • 流的方式比new一个对象克隆对象效率更高

缺点:

  • 克隆对象类必须要重写clone方法
  • 如果克隆对象依赖对象的嵌套层级较多,并且要达到深克隆,代码较复杂
  • clone 方法位于类的内部,当对已有类进行改造的时候,可能需要修改代码,违背了开闭原则

适用场景:

  • 保存对象的状态并且对象占用内存较少
  • 对象创建成本高,耗用的资源比较多
  • 对象初始化复杂

你的收藏和点赞就是我最大的创作动力,关注我我会持续输出更新!

友情提示:请尊重作者劳动成果,如需转载本博客文章请注明出处!谢谢合作!

【作者:我爱吃菠菜 】
在这里插入图片描述

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

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

相关文章

pytorch-nn.Module

目录 1. nn.Module2. nn.Sequential容器3. 网络参数parameters4. Modules内部管理5. checkpoint6. train/test状态切换6. 实现自己的网络层6.1 实现打平操作6.2 实现自己的线性层 7. 代码 1. nn.Module 是所有nn.类的父类,其中包括nn.Linear nn.BatchNorm2d nn.Con…

每日一练 - OSPF协议验证机制

01 真题题目 OSPF 只有在 Hello 报文中有验证信息,OSPF 支持 MD5 密文验证. A.正确 B.错误 02 真题答案 B 03 答案解析 这个陈述是不完全正确的。首先,OSPF确实使用Hello报文来携带认证信息,但这不意味着只有Hello报文包含验证信息。 OSPF的认证机制可…

政府绩效考核第三方评估的含义

政府绩效考核第三方评估是指由独立于政府的外部机构(如专业评估公司、研究机构或非政府组织)对政府部门或其下属单位的绩效进行客观、公正、系统的评估。其主要目的是通过引入独立的第三方评估机构,对政府绩效进行科学、全面的考核&#xff0…

【AIGC调研系列】Qwen2与llama3对比的优势

Qwen2与Llama3的对比中,Qwen2展现出了多方面的优势。首先,从性能角度来看,Qwen2在多个基准测试中表现出色,尤其是在代码和数学能力上有显著提升[1][9]。此外,Qwen2还在自然语言理解、知识、多语言等多项能力上均显著超…

肺结节14问,查出肺结节怎么办?哪些能用中医调治消散?快来了解一下吧

近些年,随着大众防癌意识的加强,和胸部低剂量CT的普及,肺结节的检出率也逐年升高,不少患者CT报告上,写着“肺小结”“肺部磨玻璃结节”的字样,当你看到这几个字时,会不会瞬间紧张起来&#xff1…

编程规范-代码检测-格式化-规范化提交

适用于vue项目的编程规范 – 在多人开发时统一编程规范至关重要 1、代码检测 --Eslint Eslint:一个插件化的 javascript 代码检测工具 在 .eslintrc.js 文件中进行配置 // ESLint 配置文件遵循 commonJS 的导出规则,所导出的对象就是 ESLint 的配置对…

简化电动汽车充电器和光伏逆变器的高压电流检测

在任何电气系统中,电流都是一个至关重要的参数。电动汽车 (EV) 充电系统和太阳能系统都需要检测电流的大小,以便控制和监测功率转换、充电和放电。电流传感器通过监测分流电阻器上的压降或导体中电流产生的磁场来测量电流。 金属氧化物半导体场效应晶体…

DBeaver连接MySQL提示“Public Key Retrieval is not allowed“问题的解决方式

问题描述 客户端root用户连接数据库出现出现Public Key Retrieval is not allowed 原因分析: 加上allowPublicKeyRetrievalfalse: 解决方案: allowPublicKeyRetrievaltrue:

Java Web学习笔记14——BOM对象

BOM: 概念:浏览器对象模型(Browser Object Model),允许JavaScript与浏览器对话,JavaScript将浏览器的各个组成部分封装为对象。 组成: Window:浏览器窗口对象 介绍:浏览…

opencv锐化卷积核的定义和应用(图像锐化)。

定义锐化卷积核 卷积核(Kernel)是一个小矩阵,它用于在图像处理操作中,比如模糊、锐化、边缘检测等。卷积核通过卷积操作应用于图像像素,产生新的图像。 在锐化操作中,我们通常使用一个 3x3 的卷积核。以下…

注解 - @RestController

注解简介 在今天的每日一注解中,我们将探讨RestController注解。RestController是Spring框架中的一个组合注解,方便创建RESTful Web服务。 注解定义 RestController注解是Controller和ResponseBody注解的组合,用于定义RESTful控制器。以下是…

物联网(IoT)及物联网网络协议面试题及参考答案(2万字长文)

什么是物联网(IoT)? 物联网(Internet of Things,简称IoT)是一个由互联网、传统电信网、传感器网络等多种网络组成的网络概念。它允许物体与物体、物体与人、人与人之间通过智能传感器、软件和网络进行信息交换和通信,实现智能化识别、定位、跟踪、监控和管理。物联网的…

光伏电站鸟害解决方案,列式冲击波声压光伏驱鸟器

光伏电站的运营过程中,最怕遇上鸟粪污染。鸟粪不仅难以清洗,还可能导致光伏组件损坏、降低发电效率。因此,制定并实施有效的驱鸟策略对于光伏电站的稳定运营至关重要。 针对光伏电站的鸟害问题,我们可以从以下几个方面来解决&…

知名优秀定制线缆生产源头工厂推荐-精工电联:全程跟踪监制,打造水下机器人线缆定制新标杆

在科技飞速发展的今天,精工电联作为高科技智能化产品及自动化设备专用连接线束和连接器配套服务商,始终站在行业前沿。我们专注于为高科技行业提供高品质、优匹配的集成线缆和连接器定制服务,特别是在水下机器人线缆定制领域,通过…

CAN的TP模式和COM模式的区别

CAN的TP(传输协议)模式和COM(通信)模式主要涉及汽车网络中的数据传输机制,两者在功能、寻址方式和帧类型等方面有所不同。具体分析如下: 功能 TP模式:TP模式,即传输协议模式&#…

sql死锁分析

一、重要参数 获取事务信息:SELECT * FROM information_schema.INNODB_TRX; 获取锁等待:SELECT * FROM information_schema.INNODB_LOCK_WAITS; 查看锁信息:SELECT * FROM information_schema.INNODB_LOCKS WHERE lock_trx_id IN () 二、case1:间隙锁和x锁互斥导致死锁 1、背景…

安全高效海外仓系统:中小海外仓标准化管理的第一步

在当今全球化的商业背景中,可以说海外仓已经成为跨境电商供应链中不可或缺的一环。 尤其是对于那些处于成长阶段的中小型海外仓来说,选择一款安全高效并且符合其海外仓规模特点的wms管理系统尤其重要。 今天我们就来系统的了解一下,安全高效…

大厂AI团战高考作文,华师一附中特级教师这样打分

在人工智能的浪潮中, 人们不禁疑问: AI真的能超越人类吗? 这究竟是现实还是幻想? 我们将目睹一场前所未有的较量: 百度文心一言、阿里通义千问、 腾讯混元、字节豆包 四家国内顶尖互联网企业 精心打造的AI大模…

HBM简介

1、什么是HBM HBMHigh Bandwidth Memory 是一种用于某些 GPU的 3D 堆叠 DRAM存储器 (动态随机存取存储器)以及服务器、高性能计算 (HPC) 、网络连接的内存接口。其实就是将很多个DDR芯片堆叠在一起后和GPU封装在一起,实…

ROS socketcan_bridge使用说明

ROS socketcan_bridge使用说明(以ubuntu20.04为例) socketcan_bridge是什么 ROS针对socketcan提供了三个层次的驱动库,分别是ros_canopen,socketcan_bridge和socketcan_interface。 socketcan_interface: 功能&#x…