03-JAVA设计模式-原型模式

原型模式

什么是原型模式

Java原型模式(Prototype Pattern)是一种创建型设计模式,其核心理念在于通过复制(克隆)已有的对象来创建新的对象,而不是通过构造函数来创建。
该模式可以显著提高对象创建的效率,特别是在需要频繁创建对象或对象创建过程较为复杂的场景下。

在原型模式中,原型对象作为基础对象,其他对象通过复制这个原型对象来创建新的实例。复制过程可以是浅克隆或深克隆。

  • 浅克隆创建一个新对象,新对象的属性和原对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆则更为彻底,不仅创建新对象,而且属性中引用的其他对象也会被克隆,不再指向原有对象的内存地址。

注意:发生浅拷贝主要针对数据类型为引用类型。

使用场景及特点

  • 当通过new产生一个对象需要非常反锁的数据准备及访问权限时,则可以使用原型模式
  • 就是java中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具备原型对象的特点。
    • 优势:效率高(直接克隆,避免了重新执行构造过程的步骤)
  • 克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值,克隆对象的属性完全与原型对象相同,并且克隆出的新对象改变不会影响原型对象,然后再修改克隆对象的值。

原型模式实现

  • Cloneable接口和clone方法
  • 原型模式中实现起来最为困难的地方就是内存复制操作,然而在Java中提供了对象的clone()方法替我门做了绝大部分事情。

案例

使用原型模式,必须实现Cloneable接口,重写protected Object clone()方法

浅拷贝

Address.java

//地址
public class Address {private String city;public Address(String city) {this.city = city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {return "Address{" +"city='" + city + '\'' +'}';}
}

Person.java

// 浅拷贝
// 实现Cloneable接口 重写protected Object clone()方法
public class Person implements Cloneable{private String name;private Address address;public Person(String name, Address address) {this.name = name;this.address = address;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();   // 默认浅拷贝}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", address=" + address +'}';}
}

TestClient.java

public class TestClient {public static void main(String[] args) throws CloneNotSupportedException {Person person = new Person("张三",new Address("北京"));Person clone = (Person) person.clone();System.out.printf("浅拷贝-原型对象:%s%n",person);System.out.printf("浅拷贝-拷贝对象值:%s%n",clone);System.out.println("======修改原型对象-address======");person.getAddress().setCity("重庆");System.out.printf("浅拷贝-原型对象:%s%n",person);System.out.printf("浅拷贝-拷贝对象值:%s%n",clone);System.out.println("======修改拷贝对象-address======");clone.getAddress().setCity("广州");System.out.printf("浅拷贝-原型对象:%s%n",person);System.out.printf("浅拷贝-拷贝对象值:%s%n",clone);}
}

执行结果:

在这里插入图片描述

图解

在这里插入图片描述

浅拷贝时,当修改原型对象时,拷贝的对象引用仍然指向原型对象的引用,因此修改原型对象,会导致拷贝对象的值发生改变
修改拷贝对象的属性时,则会在堆内存中创建一个新的地址存储新设置的值,拷贝对象引用指向新的引用地址,但不会改变原型对象的引用地址。

深拷贝

Address.java 实现Cloneable接口,重新clone()

// 地址
public class Address implements Cloneable{private String city;public Address(String city) {this.city = city;}public void setCity(String city) {this.city = city;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic String toString() {return "Address{" +"city='" + city + '\'' +'}';}
}

修改Person clone()方法

// 深拷贝
public class Person implements Cloneable{private String name;private Address address;public Person(String name, Address address) {this.name = name;this.address = address;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}@Overrideprotected Object clone() throws CloneNotSupportedException {Person clone = (Person) super.clone();clone.address = (Address) this.getAddress().clone();return clone;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", address=" + address +'}';}
}

TestClient2.java

public class TestClient2 {public static void main(String[] args) throws CloneNotSupportedException {Person person = new Person("张三",new Address("北京"));Person clone = (Person) person.clone();System.out.printf("深拷贝-原型对象:%s%n",person);System.out.printf("深拷贝-拷贝对象值:%s%n",clone);System.out.println("======修改原型对象-address======");person.getAddress().setCity("重庆");System.out.printf("深拷贝-原型对象:%s%n",person);System.out.printf("深拷贝-拷贝对象值:%s%n",clone);System.out.println("======修改拷贝对象-address======");clone.getAddress().setCity("广州");System.out.printf("深拷贝-原型对象:%s%n",person);System.out.printf("深拷贝-拷贝对象值:%s%n",clone);}
}

执行结果:

在这里插入图片描述

图解

在这里插入图片描述

利用序列化和反序列化完成深克隆

通过序列化及反序列化实现深克隆必须实现Serializable接口
Person.java

public class Person implements Serializable {private String name;private Address address;public Person(String name, Address address) {this.name = name;this.address = address;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", address=" + address +'}';}
}

Address.java

// 地址
public class Address implements Serializable {private String city;public Address(String city) {this.city = city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {return "Address{" +"city='" + city + '\'' +'}';}
}

TestClient3.java

public class TestClient3 {public static void main(String[] args) throws CloneNotSupportedException, Exception {Person person = new Person("张三",new Address("北京"));// 通过序列化 反序列化实现深拷贝byte[] bytes = null;Person clone = null;// 序列化try( ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);){oos.writeObject(person);bytes = baos.toByteArray();}// 反序列化try( ByteArrayInputStream bais = new ByteArrayInputStream(bytes);ObjectInputStream ois = new ObjectInputStream(bais);){clone = (Person) ois.readObject();}System.out.printf("深拷贝-原型对象:%s%n",person);System.out.printf("深拷贝-拷贝对象值:%s%n",clone);System.out.println("======修改原型对象-address======");person.getAddress().setCity("重庆");System.out.printf("深拷贝-原型对象:%s%n",person);System.out.printf("深拷贝-拷贝对象值:%s%n",clone);System.out.println("======修改拷贝对象-address======");clone.getAddress().setCity("广州");System.out.printf("深拷贝-原型对象:%s%n",person);System.out.printf("深拷贝-拷贝对象值:%s%n",clone);}
}

执行结果:

在这里插入图片描述

gitee源码

git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

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

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

相关文章

HTML+CSS+JavaScript网页制作案例教程第2版-黑马程序员-第7章动手实践

7.6 动手实践 学习完前面的内容&#xff0c;下面动手实践一下吧。 请结合给出的素材&#xff0c;运用元素的浮动和定位实现图7-49所示的“焦点图”效果。 链接&#xff1a;https://pan.baidu.com/s/1H98ySBSkd8h3IRA19AV2mw?pwd1024 提取码&#xff1a;1024 index.html <…

代码随想录|Day34|动态规划03|343.整数拆分、96.不同的二叉搜索树

343.整数拆分 动规五步&#xff1a; 确定 dp[i] 含义&#xff1a;拆分数字 i&#xff0c;可以获得的最大乘积为 dp[i]。递推公式&#xff1a;dp[i] max(j * (i - j), j * dp[i - j])。i 可以被拆解为两个数&#xff08;j 和 i - j&#xff09;或者多个数&#xff08;j 和 dp[i…

KMP刷leetcode速通

前言 KMP真厉害&#xff0c;刷题刷到 28.找出字符串中第一个匹配项的下标 和 1668.最大重复子字符串 next 数组用来匹配不上时&#xff0c;前缀 j j j 可以快速回退到 n e x t [ j − 1 ] next[j-1] next[j−1] 的位置。 void getNext(vector<int>& next, const…

5毛钱的DS1302 N/Z串行实时时钟IC

推荐原因&#xff1a; 便宜&#xff0c;够用 该器件最早为DALLAS的产品&#xff0c;所以冠有DS&#xff0c;现国内有多个厂家生产&#xff0c;部分价格不到5毛钱的含税价格&#xff0c;有此自行车&#xff0c;还要什么宝马&#xff1f; 下述为简介&#xff0c;使用前请参阅相应…

Linux 网络配置 主机名解析过程

Windows查看网络信息 ipconfigLinux中查看网络配置&#xff1a; ifconfigVMware的网络编辑器&#xff1a; 测试两台主机网络是否连通&#xff1a; ping ip地址自动获取IP 自动获取IP&#xff0c;可以避免IP冲突&#xff0c;但IP可能会变&#xff0c;使用图形界面&#xf…

xilinx AXI CAN驱动开发

CAN收发方案有很多&#xff0c;常见的解决方案通过是采用CAN收发芯片&#xff0c;例如最常用的SJA1000,xilinx直接将CAN协议栈用纯逻辑实现&#xff0c;AXI CAN是其中一种&#xff1b; 通过这种方式硬件上只需外接一个PHY芯片即可 上图加了一个电平转换芯片 软件设计方面&…

书生·浦语大模型-第三节课笔记/作业

笔记 作业 原版 prompt控制节奏&#xff0c;实现类似关键词检索、主题、信息抽取等功能注意这里根据llm返回的topic (prompt: 告诉我这句话的主题&#xff0c;直接说主题不要解释)进行召回检索(CacheRetriever), 并再次让大模型判断query与返回的检索的相关程度. 如果本地检索…

蓝桥杯 子串简写(暴力)

题目&#xff1a;子串简写 代码1&#xff1a; #include<algorithm> #include<iostream> #include<cstring> #include<queue> #include<cmath>using namespace std;char c1,c2; int k; char s[100010]; int a[100010]; int b[100010]; int cnt; …

Nginx服务 高级配置

五、高级配置 1. 网页的状态页 基于 nginx 模块 ngx_http_stub_status_module 实现&#xff0c;在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module&#xff0c;否则配置完成之后监测会是提示语法错误注意。状态页显示的是整个服务器的状态&#xff0c;而…

Python学习之-logging模块及彩色日志详解

前言&#xff1a; Python的logging模块是内建的、功能强大的日志系统&#xff0c;可通过简单的配置&#xff0c;就能满足基本到复杂的日志管理需求。它可以让你以各种方式记录错误、调试信息、以及其他运行时的信息&#xff0c;这些都是应用程序健壯性、可维护性的关键。 1 基…

分公司=-部门--组合模式

1.1 分公司不就是一部门吗&#xff1f; "我们公司最近接了一个项目&#xff0c;是为一家在全国许多城市都有分销机构的大公司做办公管理系统&#xff0c;总部有人力资源、财务、运营等部门。" "这是很常见的OA系统&#xff0c;需求分析好的话&#xff0…

CTK插件框架学习-服务工厂(06)

CTK插件框架学习-信号槽(05)https://mp.csdn.net/mp_blog/creation/editor/137240105 一、服务工厂定义 注册插件时使用服务工厂注册&#xff0c;使用getService根据调用者插件资源文件内容获取在服务工厂内的对应实现在服务工厂中可以知道是哪个插件正在调用服务工厂懒汉模式…

Day5-Hive的结构和优化、数据文件存储格式

Hive 窗口函数 案例 需求&#xff1a;连续三天登陆的用户数据 步骤&#xff1a; -- 建表 create table logins (username string,log_date string ) row format delimited fields terminated by ; -- 加载数据 load data local inpath /opt/hive_data/login into table log…

开源免费的多功能PDF工具箱

它支持修改PDF、编辑PDF书签、导出PDF书签、导入书签、生成、合并、拆分、提取页面内容、提取图片、OCR 功能介绍: 修改PDF信息&#xff1a;修改文档属性、页码编号、页面链接、页面尺寸&#xff1b;删除自动打开网页等动作&#xff0c;去除复制及打印限制&#xff1b;设置阅读…

别再抱怨学鸿蒙没方向了! 这鸿蒙全栈(南北双向)开发学习路线收藏好!

在互联网技术不断发展的现在&#xff0c;鸿蒙操作系统的出现标志着是能技术领域的一次重大突破&#xff0c;鸿蒙作为华为推出的一代操作系统&#xff0c;鸿蒙不仅达代表了自主创新的力量&#xff0c;还因为独特的分布式架构和全场景适配能力而备受关注。随着鸿蒙生态的不断完善…

2024.4.7周报

摘要 在本周阅读的文献中&#xff0c;提出了基于Transformer的GAN模型&#xff0c;GAN的生成器和鉴别器&#xff0c;都是基于Transformer的编码器架构构建的&#xff0c;通过处理图像的方式处理时间序列数据作为该模型的输入。该模型能够生成各种长度的多维时间序列数据&#…

7.1.4 Selenium 爬取京东商品信息实战

目录 1、实战内容 2、思路 3、分析 url 4、开始操作 1、得到 Cookies 2、访问页面&#xff0c;得到 response 3、解析页面 4、存入 MySQL 5、1-3步总代码 1、实战内容 爬取京东笔记本电脑商品的信息(如&#xff1a;价格、商品名、评论数量)&#xff0c;存入 MySQL 中…

11-新热文章-实时计算

热点文章-实时计算 1 今日内容 1.1 定时计算与实时计算 1.2 今日内容 kafkaStream 什么是流式计算 kafkaStream概述 kafkaStream入门案例 Springboot集成kafkaStream 实时计算 用户行为发送消息 kafkaStream聚合处理消息 更新文章行为数量 替换热点文章数据 2 实时…

能源照明运作机制与智能调控技术实现途径

随着城市化进程的加速&#xff0c;智慧城市已成为现代城市发展的重要方向。能源照明作为城市基础设施的重要组成部分&#xff0c;其运作机制与智能调控技术的实现对于提高城市能源利用效率、促进可持续发展具有重要意义。 能源照明是一个涵盖广泛、错综复杂的领域&#xff0c;它…

Redis中的集群(一)

集群 概述 Redis集群是Redis提供的分布式数据库方案&#xff0c;集群通过分片(sharding)来进行数据共享&#xff0c;并提供复制和故障转移功能 节点 一个Redis集群通常由多个节点(node)组成&#xff0c;在刚开始的时候&#xff0c;每个节点都是相互独立的&#xff0c;它们都…