概述

原型模式是为了解决一些不必要的对象创建过程。当Java JDK中提供了Cloneable接口之后,原型模式就变得异常的简单了。虽然由于Cloneable的引入使用程序变得更简单了,不过还是有一些需要说明和注意的东西在里面的。文本就详细讲解一下这些注意事项吧。

版权说明

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
本文作者:Q-WHai
发表日期: 2016年3月3日
本文链接:https://qwhai.blog.csdn.net/article/details/50787390
来源:CSDN
更多内容:分类 >> 设计模式

拷贝技术详解

1.对象赋值

如果现在有一个Student对象s1,当我们使用s2=s1的方式对s2进行赋值时,实则是将s1对象的引用复制给了s2。过程如下:

图-1 对象赋值内存分析图

所以,对于s1与s2它们所指内存应该为同一块区域。下面为此两个“对象”所占用的内存地址:

org.design.pattern.prototype.model.Student@659e0bfd
org.design.pattern.prototype.model.Student@659e0bfd

2.浅拷贝

什么是浅拷贝?浅拷贝后的结果是对象的内存地址变化了(对象的引用发生了变化),可对象中包含的对象内存则没有变化。

图-2 对象拷贝内存分析图

大家看到上面的分析图是不是有一些疑惑?为什么name发生了变化,而friends却没有变化呢?

这里先不用说其他的数据类型(int, double, char, short, long, float, byte),我们知道String类型的对象是不可变对象,当我们对不可变对象进行赋值时,它会另外开辟一个新对象。因为这个特性可能会影响到我们对Cloneable的正确判断,所以这里需要使用一个可变对象来进行实验。我选择的是:List。

假使初始状态是:s1有两个朋友,小红和小梅。当我们使用List的可变性向s2的朋友List中添加了一个新朋友时,理论上只是s2的朋友被修改了,可是实事上并非如此,以下为实验结果:

初始的List对象:
s1.friends: [小红, 小梅]
s2.friends: [小红, 小梅]不改变List对象:
s1.friends: [小红, 小梅, 小刚]
s2.friends: [小红, 小梅, 小刚]重新对List对象赋值:
s1.friends: [小红, 小梅, 小刚]
s2.friends: null

从实验中我们可以看到如果我们对可变对象进行对象内部的可变操作时,拷贝的对象和被拷贝的对象都会被修改。单从这一点,我们就可以断定,Cloneable的拷贝属于浅拷贝。你是不是要问了,那怎么样才能实现对象的深拷贝呢?请接着往下看。

3.深拷贝

上面说到对象的浅拷贝,在拷贝中我们对可变对象的操作有一些棘手。而深拷贝则可以解决这个问题。深拷贝的实现要依赖与对象的持久化操作。更多关于对象持久化的内容可参见本人另一篇博客:《网络爬虫:基于对象持久化实现爬虫现场快速还原》。

对象持久化是说把一个对象写到文件中(或是向网络,或是向进程之间进行传输),当我们需要拷贝一个对象时,先把此对象固化到文件,再从文件中读取对象。这样一个过程就完成了对象的深拷贝,在博客《网络爬虫:基于对象持久化实现爬虫现场快速还原》中我也有详细地说明,这里就不再赘述了。

原型模式实现

终于可以说本文的主题(原型模式)了。

原型模式是基于对象的拷贝的,可以是浅拷贝也可以是深拷贝操作。也就是说当我们需要批量生成某一对象,就可以事先创建一个对象的原型,再通过对象的拷贝操作批量生成对象。原型模式的实现类图如下:

图-3 原型模式类图

性能测试

这里我们测试一下原型模式的性能。

public static void pressureTesting() throws CloneNotSupportedException {int times = 100000000;Student student = new Student("小明");student.addFriend(new People("Friend-A"));student.addFriend(new People("Friend-B"));student.addFriend(new People("Friend-C"));student.addFriend(new People("Friend-D"));student.addFriend(new People("Friend-E"));long startStamp = System.currentTimeMillis();for (int i = 0; i < times; i++) {student.clone();}long currentStamp = System.currentTimeMillis();System.out.println("TIME USED: " + (currentStamp - startStamp) + " ms");startStamp = System.currentTimeMillis();for (int i = 0; i < times; i++) {Student student2 = new Student("小红");student2.addFriend(new People("Friend-A"));student2.addFriend(new People("Friend-B"));student2.addFriend(new People("Friend-C"));student2.addFriend(new People("Friend-D"));student2.addFriend(new People("Friend-E"));}currentStamp = System.currentTimeMillis();System.out.println("TIME USED: " + (currentStamp - startStamp) + " ms");}

运行结果:

TIME USED: 1752 ms
TIME USED: 4352 ms

从上面的运行结果可以看出,这里如果使用 new 进行构建新对象,在性能上要慢不少。这是因为 clone 是直接针对内存操作的。但是,这里也有一个问题,对于 array 数组而言,因为这是一个浅拷贝的操作,所以还要对 array 进行特殊处理,不然可能就会导致所有对象的 array 是同一个对象。

Ref

  • 《23种Java设计模式》
  • 《编写高质量代码 : 改善Java程序的151个建议》

Github源码下载

https://github.com/qwhai/design-pattern

征集

如果你也需要使用ProcessOn这款在线绘图工具,可以使用如下邀请链接进行注册:
https://www.processon.com/i/56205c2ee4b0f6ed10838a6d

Java设计模式——原型模式相关推荐

  1. Java设计模式-原型模式

    原型模式   在有些系统中,存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂且耗时耗资源,用原型模式生成对象就很高效. 原型模式的定义与特点   原型(Prototype) ...

  2. 我的Java设计模式-原型模式

    "不好意思,我是卧底!哇哈哈哈~"额......自从写了上一篇的观察者模式,就一直沉浸在这个角色当中,无法自拨.昨晚在看<使徒行者2>,有一集说到啊炮仗哥印钞票,我去, ...

  3. 7.Java设计模式-----原型模式(Prototype Pattern)

    什么是原型模式? 原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式是实现了一个原型接口 ...

  4. Java设计模式--原型模式

    1 Prototype Pattern 原型模式 目的:在运行期通过"复制和粘贴"来创建新对象 : 实现:创建一个原型对象,再通过Java 语言中常用的克隆实现方法复制这个原型对象 ...

  5. java设计模式---原型模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述原型(Prototype)模式的: 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办 ...

  6. Java设计模式--原型模式Prototype

    原型模式Prototype 原型模式使得用户可以通过复制对象样本来创建新对象.与通过调用构造函数创建对象相比,二者主要区别在于:通过复制创建的新对象一般会包含原始对象的某些状态. 原型模式属于对象的创 ...

  7. Java常用设计模式————原型模式(一)

    介绍 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. 原型模式用于创建重复的对象,同时又能保证性能.当直接创建对象的代价比较大时,则采用 ...

  8. 设计模式 原型模式_创新设计模式:原型模式

    设计模式 原型模式 原型模式用于创建对象的副本. 这种模式非常有用,特别是当从头开始创建对象的成本很高时. 与builder , factory和abstract factory模式相比,它不会从头开 ...

  9. 设计模式 原型模式_设计模式:原型

    设计模式 原型模式 创新设计模式之一是原型设计模式 . 尽管原型是创造模式,但它在概念上与其他模式有所区别. 我的意思是原型在某种意义上创造了自己. 我将在下面解释. 原型模式的所有魔力都基于Java ...

最新文章

  1. Java基础--二维数组
  2. Leetcode 112. 路径总和 (每日一题 20210910)
  3. oracle删除一个用户
  4. leetcode-283-移动零
  5. 推荐系统-基于矩阵分解的LFM模型
  6. MySql 错误 Err [Imp] 1153 - Got a packet bigger than 'max_allowed_packet' bytes
  7. java打印已经被加载的类_使用URLClassLoader加载类,不会报错,但被加载类中的内容也没有打印出来...
  8. flink sql设置并行度_Flink集成Hivestream模式用例
  9. webStrom破解链接
  10. OSError: cannot identify image file
  11. 学前端的记录帖html+css b站千峰19版
  12. 微信朋友圈 腾讯服务器,朋友圈@微信能得一面红旗?腾讯服务器一度宕机
  13. Unity粒子系统——简易特效制作(三)
  14. 【洛谷T2695 桶哥的问题——吃桶】
  15. Linux安装zabbix4
  16. 编译程序和解释程序的区别
  17. 基础连接已关闭解决办法_手机wifi连不上怎么办 手机wifi连不上解决办法【详解】...
  18. Leetcode_24_Swap Nodes in Pairs
  19. scConverter 文档转换 DLL / SDK
  20. P2P第三方资金托管平台

热门文章

  1. python—多进程之进程的创建(一)
  2. 【Win32汇编】MOVS,STOS,REP 指令
  3. [watevrCTF 2019]Repyc [NPUCTF2020]BasicASM
  4. PE学习(九)第九章:TLS 动态TLS与静态TLS
  5. C语言经典算法 11-20
  6. Java之主数据类型的包装
  7. ArrayBlockingQueue队列
  8. python爬虫beautifulsoup爬当当网_Python爬虫包 BeautifulSoup 递归抓取实例详解_python_脚本之家...
  9. ospf hello时间和dead_使用OSPF协议使SPOKE端正常通信
  10. mysql 集群_MySQL之PXC集群搭建