[设计模式] ------ 原型模式(浅拷贝和深拷贝)
原型模式
原型模式就是使用复制对象,创建出新的对象,并且不需要知道创建的细节(比如类的属性的赋值等等)。
基本使用(浅拷贝)
常见的就是使用Object的clone方法。需要让类实现Cloneable并重写clone方法,才能使用。
public class A implements Cloneable{private String code;private String name;public A(String code, String name) {this.code = code;this.name = name;}public void setCode(String code) {this.code = code;}@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}public static void main(String[] args) throws CloneNotSupportedException {A a = new A("00","name1");A a1 = (A)a.clone();a1.setCode("01");A a2 = (A)a.clone();a2.setCode("02");System.out.println(a.hashCode());System.out.println(a1.hashCode());System.out.println(a2.hashCode());}
}
结果,很明显,三个对象是不一样的。
596512129
824318946
930990596
深拷贝
上面那种方式,是浅拷贝,即只能拷贝A类中的基本数据类型和String。对于A类中如果还有其他引用类型,浅拷贝是实现不了引用类型的拷贝的。
所以,需要进行对A深拷贝B,通常有两种方法(重写Clone方法和序列化)。
方法1、重写A的clone方法,并在方法中对B进行拷贝(当然B类中也要实现浅拷贝)。
public class B implements Serializable,Cloneable{private String id;@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class A implements Serializable,Cloneable{private String code;private String name;private B b;public A(String code, String name, B b) {this.code = code;this.name = name;this.b = b;}public void setCode(String code) {this.code = code;}@Overridepublic Object clone() throws CloneNotSupportedException {A a = (A)super.clone();// 在A的clone方法中,对A的B引用进行clonea.b = (B)a.b.clone();return a;}public static void main(String[] args) throws CloneNotSupportedException {A a = new A("00","name1",new B());A a1 = (A)a.clone();a1.setCode("01");A a2 = (A)a.clone();a2.setCode("02");System.out.println(a.b.hashCode());System.out.println(a1.b.hashCode());System.out.println(a2.b.hashCode());}
}
执行结果:
596512129
824318946
930990596
看执行结果,每个A实例的B引用,都是不同的hashCode值,说明A中的B也被拷贝了。
如果将A中clone方法中的a.b = (B)a.b.clone();注释掉,可以得到最终打印出来的三个结果就是一样的。
方法2、序列化
序列化前提,A和B都要实现Serializable接口。
A和B的定义还是和方法1一样,我们只重写A中的clone方法。
@Overridepublic Object clone() throws CloneNotSupportedException {ByteArrayOutputStream bos = null;ObjectOutputStream oos = null;ByteArrayInputStream bis = null;ObjectInputStream ois = null;try {//序列化,以对象的方式输出去bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);oos.writeObject(this);//反序列化,再以对象的方式写回来,所有的引用类型自然都会带上了bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);A copyResult = (A)ois.readObject();return copyResult;} catch (Exception e) {e.printStackTrace();}finally {try {bos.close();oos.close();bis.close();ois.close();} catch (IOException e) {e.printStackTrace();}}return null;}
最终效果也是随着A的clone,A中的B引用也被clone出新的一份来了。
上面的这个序列化只是一种实现思路,也可以用fastjson将A对象转成json字符串,再反转成A返回去,其实原理都是一样的。
实际应用场景
其实很好找,只要找到哪些类实现了Cloneable接口,大概率就是用到了所谓了原型模式。
比如Spring的Bean的创建,我都都知道默认是单例模式,那其实还可以知道Bean是多例的,这个就用到了原型模式。
[设计模式] ------ 原型模式(浅拷贝和深拷贝)相关推荐
- 【设计模式】原型模式 ( 浅拷贝 | 深拷贝 | 原型与单例冲突 | 禁用 final )
文章目录 I . 原型模式 总结 II . 原型模式 浅拷贝 III . 原型模式 深拷贝 IV . 原型模式 与 单例 V . 原型模式 中的 final 关键字 ( 禁止出现 ) I . 原型模式 ...
- Java常用设计模式————原型模式(一)
介绍 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. 原型模式用于创建重复的对象,同时又能保证性能.当直接创建对象的代价比较大时,则采用 ...
- C++设计模式——原型模式(Prototype Pattern)
C++设计模式--原型模式(Prototype Pattern) 微信公众号:幼儿园的学霸 目录 文章目录 C++设计模式--原型模式(Prototype Pattern) 目录 定义 代码示例 普通 ...
- 设计模式-原型模式(克隆羊多利看了都说好)
文章目录 引例 原型模式 浅拷贝 深拷贝 引例 标题无意冒犯 在介绍原型模式前,我们先从实际问题出发,对比解决方法前后优劣点. 问题: 现在有一只羊(包含属性:名字Dolly.年龄2),需要克隆10只 ...
- 设计模式 原型模式_创新设计模式:原型模式
设计模式 原型模式 原型模式用于创建对象的副本. 这种模式非常有用,特别是当从头开始创建对象的成本很高时. 与builder , factory和abstract factory模式相比,它不会从头开 ...
- 设计模式 原型模式_设计模式:原型
设计模式 原型模式 创新设计模式之一是原型设计模式 . 尽管原型是创造模式,但它在概念上与其他模式有所区别. 我的意思是原型在某种意义上创造了自己. 我将在下面解释. 原型模式的所有魔力都基于Java ...
- 设计模式 原型模式_原型设计模式:创建另一个小车
设计模式 原型模式 创建对象确实是一个耗时的过程,也是一件昂贵的事情. 因此,我们现在正冒险节省时间和金钱. 我们该怎么做? 克隆奇迹多莉 有人记得多莉吗? 是的,是绵羊,是第一个被克隆的哺乳动物. ...
- 第六章 Caché 设计模式 原型模式
文章目录 第六章 Caché 设计模式 原型模式 定义 使用场景 优点 结构图 描述 示例 初级写法 缺点 中级写法 缺点 高级写法 (浅复制) 浅复制 深复制 完整示例 简历类(复制类) 对象类(工 ...
- [设计模式]原型模式
简介 原型模式 (Prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式是一种对象创建型模式 (可参考 设计模式 创建型模式). 结构 图-原型模式结构图 Pr ...
最新文章
- PHPCMS v9设置文章的审核功能
- TypeScript Partial 使用的一个小技巧
- 使用SQL Server分区表功能提高数据库的读写性能
- 在存储过程中编写正确的事务处理代码
- mrql初级教程-使用(er)
- axios的拦截器(Interceptors)
- C语言目录和文件操作扩展
- 关于SimpleITK 使用函数sitk.WriteImage报错‘ERROR (nifti_image_write_hdr_img2): cannot open output file ‘
- centos7下安装libiconv失败
- 简单的Site to site ipsec ×××实验
- 大数据分析对物联网发展有什么影响
- 邮箱发大文件服务器怎么删除,Exchange 2010如何删除系统默认邮箱数据库
- 在面试时应该如何自我介绍?
- 【产品经理】 产品经理进阶之路(十一):怎么看微信的公众号和百度的直达号,哪个更有优势
- 用Win32DiskImager写入U盘容量变小,恢复容量方法
- 中国IT工作者35岁后的发展出路调查报告(4)
- 三款ActiveX图表控件对比评测 Pro ActiveX、ProEssentials、ChartDirector
- LeetCode 2309. 兼具大小写的最好英文字母
- 韦东山第1期-学习笔记-2
- Android端乐橙云SDK集成