【设计模式】 - 创建者模式 - 原型模式

news2025/3/1 18:24:25

目录标题

  • 1. 原型模式
    • 1.1 概述
    • 1.2 结构
    • 1.3 实现
    • 1.4 浅克隆
      • Demo1:基本类型
      • Demo2:引用类型
      • 浅克隆总结:
    • 1.5 深克隆
      • 实现方式1:浅克隆嵌套
        • 1. Address类实现Cloneable接口,重写clone方法;
        • 2. 在Customer类的clone方法中调用Address类的clone方法
      • 实现方式2:序列化
    • 总结

1. 原型模式

1.1 概述

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

1.2 结构

抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
访问类:使用具体原型类中的 clone() 方法来复制新的对象。
在这里插入图片描述

1.3 实现

在Java中对象的克隆有深克隆和浅克隆之分。有这种区分的原因是Java中分为基本数据类型和引用数据类型,对于不同的数据类型在内存中的存储的区域是不同的。基本数据类型存储在栈中,引用数据类型存储在堆中。

浅克隆:创建一个新对象,对于基本数据类型和String类型属性(拷贝一份该对象并重新分配内存,即产生了新的对象);对于非基本数据类型,浅克隆并不会克隆这些属性(即不会为这些属性分配内存,仍指向原有属性所指向的对象的内存地址)。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
总结:浅克隆中由于除8中数据类型和String类型外的其他类型的属性不会被克隆,因此当通过新对象对这些属性进行修改时,原对象的属性也会同时改变。而深克隆则已经对这些属性重新分配内存,所以当通过新对象对这些属性进行修改时,原对象的属性不会改变。

Java中的Object类中提供了 clone() 方法来实现浅克隆。 Cloneable 接口是上面的类图中的抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类。代码如下:

Realizetype(具体的原型类):

public class Realizetype implements Cloneable {
	public Realizetype() {
		System.out.println("具体的原型对象创建完成!");
	}
	@Override
	protected Realizetype clone() throws CloneNotSupportedException {
		System.out.println("具体原型复制成功!");
		return (Realizetype) super.clone();
	}
}

PrototypeTest(测试访问类):

public class PrototypeTest {
	public static void main(String[] args) throws CloneNotSupportedException{
		Realizetype r1 = new Realizetype();
		Realizetype r2 = r1.clone();
		System.out.println("对象r1和r2是同一个对象?" + (r1 == r2)); //ture
	}
}

1.4 浅克隆

Demo1:基本类型

在这里插入图片描述

Demo2:引用类型

public static void main(String[] args) throws CloneNotSupportedException {  
        Address address = new Address("CH" , "SD" , "QD");  
        Customer customer1 = new Customer(1 , 23 , address);  
        Customer customer2 = customer1.clone();  
        customer2.getAddress().setCity("JN");  
        customer2.setID(2);  
        System.out.println("customer1:"+customer1.toString());  
        System.out.println("customer2:"+customer2.toString());  
    }  
}  
class Customer implements Cloneable{  
    public int ID;  
    public int age;  
    public Address address;  
    //get/set...
    
    @Override  
    public Customer clone() throws CloneNotSupportedException {  
        return (Customer) super.clone();  
    }  
}  
class Address{  
    private String country;  
    private String province;  
    private String city;  
   //get/set...
}  
customer1:Customer [ID=1, age=23, address=Address [country=CH, province=SD, city=JN]]  
customer2:Customer [ID=2, age=23, address=Address [country=CH, province=SD, city=JN]]  

customer2修改了id后没有影响到customer1,但是修改了customer2的address属性的city值为JN后,发现customer1的address值也发生了改变。这样就没有达到完全复制、相互之间完全没有影响的目的。这样就需要进行深克隆。

浅克隆总结:

浅克隆对于一个只含有基本数据类型的类来说使用clone方法,是完全没有问题的。

1.5 深克隆

深克隆与浅克隆的区别就是,浅克隆不会克隆原对象中的引用类型,仅仅拷贝了引用类型的指向。深克隆则拷贝了所有。也就是说深克隆能够做到原对象和新对象之间完全没有影响。
而深克隆的实现就是在引用类型所在的类实现Cloneable接口,并使用public访问修饰符重写clone方法。

实现方式1:浅克隆嵌套

1. Address类实现Cloneable接口,重写clone方法;

@Override  
public Address clone() throws CloneNotSupportedException {  
    return (Address) super.clone();  
}

2. 在Customer类的clone方法中调用Address类的clone方法

@Override  
public Customer clone() throws CloneNotSupportedException {  
    Customer customer = (Customer) super.clone();  
    customer.address = address.clone();  
    return customer;  
}
customer1:Customer[ID=1, age=23, address=Address [country=CH, province=SD, city=QD]]
customer2:Customer[ID=2, age=23, address=Address [country=CH, province=SD, city=JN]]

发现customer2无论如何修改,customer1都没有受到影响。

实现方式2:序列化

实现深克隆的另一种方法就是使用序列化,将对象写入到流中,这样对象的内容就变成了字节流,也就不存在什么引用了。然后读取字节流反序列化为对象就完成了完全的复制操作了。

Address address = new Address("CH" , "SD" , "QD");  
Customer customer1 = new Customer(1 , 23 , address);  
Customer customer2 = (Customer) cloneObject(customer1);  
customer2.getAddress().setCity("JN");  
customer2.setID(2);  
System.out.println("customer1:"+customer1.toString());  
System.out.println("customer2:"+customer2.toString());  
public static Object cloneObject(Object obj) throws IOException, ClassNotFoundException{  
    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();  
    ObjectOutputStream out = new ObjectOutputStream(byteOut);  
    out.writeObject(obj);   
    ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());  
    ObjectInputStream in =new ObjectInputStream(byteIn);  
    return in.readObject();  
} 
customer1:Customer [ID=1, age=23, address=Address [country=CH, province=SD, city=QD]]  
customer2:Customer [ID=2, age=23, address=Address [country=CH, province=SD, city=JN]]  

总结

  1. 浅克隆:只复制基本类型的数据,引用类型的数据只复制了引用的地址,引用的对象并没有复制,在新的对象中修改引用类型的数据会影响原对象中的引用。
  2. 深克隆1:是在引用类型的类中也实现了clone,是clone的嵌套,复制后的对象与原对象之间完全不会影响。
  3. 深克隆2:使用序列化也能完成深复制的功能:对象序列化后写入流中,此时也就不存在引用什么的概念了,再从流中读取,生成新的对象,新对象和原对象之间也是完全互不影响的。

来源:深克隆和浅克隆:https://blog.csdn.net/weixin_44351616/article/details/125146241
https://www.bilibili.com/video/BV1Np4y1z7BU?p=49&spm_id_from=pageDriver&vd_source=b901ef0e9ed712b24882863596eab0ca

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

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

相关文章

[附源码]SSM计算机毕业设计智慧教室预约JAVA

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

2019年1+X 证书 Web 前端开发中级理论考试——易错题、陌生但又会考到的题目原题+答案

文章目录 🎯关于1X标准 🎯关于中级考点 ❗❗❗注意: 理论题题型包括单选题、多选题、判断题。 ❗注意:题目序号没有修改 ❗红色的选项才是正确答案 ❗如果题目后面没有红色的选项,那么括号里面的答案是正确的 …

Unity游戏Mod/插件制作教程01 - BepInEx的安装和使用

前言 本章节为没有使用过BepInEx的同学进行BepInEx的安装和使用方面的介绍,如果你之前已经使用过并了解如何使用,可以直接跳过本章节。 BepInEx下载 BepInEx的Github链接 https://github.com/BepInEx/BepInEx/releases 一共有3种版本,BepIn…

Hive环境搭建

3.1 Hive环境搭建 3.1.1 Hive引擎简介 Hive引擎包括:默认MR、tez、spark Hive on Spark:Hive既作为存储元数据又负责SQL的解析优化,语法是HQL语法,执行引擎变成了Spark,Spark负责采用RDD执行。 Spark on Hive : Hi…

人人开源后台项目maven构建(yyds)

人人开源后台项目maven构建(yyds) npm run serve 和 npm run dev 的区别在日常运行vue 项目中 在终端 运行命令有时用到 npm run serve 有时是 npm run dev。那么,什么时候用到 serve ,什么时候用到 dev 呢? 他们的区别是什么?一…

【学习笔记】《Python深度学习》第四章:机器学习基础

文章目录1 机器学习的四个分支1.1 监督学习1.2 无监督学习1.3 自监督学习1.4 强化学习2 评估机器学习模型2.1 训练集、验证集和测试集2.2 注意事项3 数据预处理、特征工程和特征学习3.1 神经网络的数据预处理3.2 特征工程4 过拟合与欠拟合4.1 减小网络大小4.2 添加权重正则化4.…

postgresql安装配置和基本操作

1.安装 linux上安装 最好是centos7.6或者7.8, 参考官网 PGSQL的官方地址:PostgreSQL: The worlds most advanced open source database PGSQL的国内社区:PostgreSQL中文社区:: 世界上功能最强大的开源数据库... 点击download PostgreSQ…

【Struts2】二_Struts2参数映射、核心配置文件struts.xml中的标签与属性的使用

文章目录Struts2一、参数映射:▶传递基本数据类型:▶传递对象二、核心配置文件struts.xml:2.1、constant标签2.2、package标签2.3、action标签三、Action配置:3.1、Action简介:3.2、继承ActionSupport类:3.…

JAVA初阶——继承和多态

目录 一、继承 1、定义: 2、用法: 3、使用从父类继承的成员 (1)、子类使用从父类继承的成员变量 (2)、子类使用从父类继承的成员方法 4、super (1)、定义: 5、子…

ID3算法

目录 ID3算法 例子 ID算法总结 ID3算法 ID3算法是在每个结点处选取能获得最高信息增益的分支属性进行分裂 在每个决策结点处划分分支、选取分支属性的目的是将整个决策树的样本纯度提升 衡量样本集合纯度的指标则是熵; 举例来说,如果有一个大小为10的…

被裁后,狂刷607页JUC源码分析笔记,立马拿蚂蚁offer

前言 可能大家最近,在公众号,或者各大自媒体平台,都能够刷到,因为疫情美国经济面临结构性衰退,美联储疯狂印钞导致世界性经济波动,导致国际环境不是很好,也间接影响到了中国,中国也…

跟艾文学编程《Python基础》(2)Python 容器

作者: 艾文,计算机硕士学位,企业内训讲师和金牌面试官,公司资深算法专家,现就职BAT一线大厂。 邮箱: 1121025745qq.com 博客:https://wenjie.blog.csdn.net/ 内容:跟艾文学编程《Pyt…

JAVA微服务场景下分布式日志收集排查问题实战

问题产生的根由?不同服务的日志存在哪里?我们怎么去排查线上问题? 问题场景:我们部署的java服务可能有几十个,不同的项目里面他是看不到别的服务的日志,只有服务的返回msg消息,相比传统的单体服…

计算机体系结构:1.1.系统加速比计算例题

文章目录题目内容题目分析题目求解题目内容 假设在某程序的执行过程中,浮点操作时间占整个执行时间的10%,现希望对浮点 操作加速 。 (1)设对浮点操作的加速比为Sf,请推导出程序总的加速比S和Sf之间的关系表达式&#…

IoU的计算实现详解(基于Python)

文章目录1. 交并比(IoU)2.原理3.代码实现1. 交并比(IoU) 具体来说,它是两边界框相交部分面积与相并部分面积之比,如下所示: 也就是两个框的交集和两个框的并集之比。 2.原理 这里详细解释一…

如何安装与配置Node.js

Node.js发布于2009年5月,由Ryan Dahl开发,是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O模型, 让JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等…

使用轻量应用服务器搭配宝塔面板搭建可道云kodbox私有云网盘的方法教程

你是否有过网盘下载速度只有十几KB,时不时出现网盘的文件被删除的问题,不如自己搭建一个云网盘吧,只需要一云服务器,即可搭建一个跟某度云一样的云盘。可以自由下载,不限制网速,随时都可上传下载。这篇文章…

nginx+redis+jvm三级缓存设计与落地实现

由于涉及到个人隐私,使用的是阿里云平台,所以下面的IP地址和密码我都做了修改。不是真实的地址。此模拟秒杀商品列表信息缓存案例实现的技术解决方案。 远程环境1版本操作系统ubuntu22.04openresty1.21.4.1jdkOracle JDK17IP192.168.1.1远程环境2版本redis7.0.5Springboot2.5…

149. SAP UI5 Table 控件数据进行 Excel 导出时如何进行格式控制

文章目录 字符串类型的显示控制数值类型(Number)的值显示控制日期和时间显示的格式控制布尔值的显示控制BigNumber 和百分比数值的显示总结本教程的前一步骤,我们成功的将 sap.m.Table 控件里显示的数据导出到了本地 Excel 文件中。 下图是使用 sap.m.Table 显示的表格页面:…

菜小白聊聊开源和开源协议

最近想入linux的深坑,于是开启了马哥sre课程的探险之旅。在了解到Linux是一款自由和开放源码的类UNIX操作系统的历史时,深深被开源精神所折服。也强烈感受到了开源精神的伟大。也正是因为有了开放源码的精神,才有了国产百花齐放的android系统…