摘要

主要介绍原型设计模式的原理,原型设计模式就是java中深拷贝和浅拷贝思想的原理。

一、新对象创建问题

现在有一只羊,姓名为 Tom,年龄为 1,颜色为白色,请编写程序创建和 Tom 羊属性完全相同的 10 只羊。

package com.zhuangxiaoyan.designpattern.clonemodel;/*** @Classname CloneModel* @Description1)优点是比较好理解,简单易操作2)在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低3)总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活* @Date 2022/3/27 9:16* @Created by xjl*/
public class CloneModel {public static void main(String[] args) {for (int i = 0; i < 10; i++) {Sheep sheep = new Sheep("Tom", 1,"白色");System.out.println(sheep);}}
}/*** @description 原型类* @param: null* @date: 2022/3/27 9:17* @return:* @author: xjl
*/
class Sheep {private String name;private Integer age;private String color;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public Sheep(String name, Integer age, String color) {this.name = name;this.age = age;this.color = color;}
}

传统方法优缺点

  • 1)优点是比较好理解,简单易操作
  • 2)在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低
  • 3)总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活

改进的思路分析

Java 中 Object 类是所有类的根类,Object 类提供了一个 clone 方法,该方法可以将一个 Java 对象复制一份,但是需要实现 clone 的 Java 类必须要实现一个接口 Cloneable,该接口表示该类能够复制且具有复制的能力 ==> 原型模式。

二、原型模式(Prototype 模式)

  • 1)原型模式(Prototype 模式)是指:用原型实例指定创建对象种类,并通过拷贝原型创建新的对象。

  • 2)原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。

  • 3)工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即对象.clone()。

  • 4)形象的理解:孙大圣拔出猴毛,变出其它孙大圣

原理结构图说明

  • 1)Prototype:原型类,声明一个克隆自己的接口
  • 2)ConcretePrototype:具体的原型类,实现一个克隆自己的操作
  • 3)Client:让一个原型对象克隆自己,创建一个新的对象(属性相同)

使用原型模式改进传统方式式,让程序具有更高的效率和扩展性

三、JDK 源码分析

Spring 框架中,创建ApplicationContext时,使用的getBean方法中使用到了原型模式

四、浅拷贝和深拷贝原理

4.1 浅拷贝基本介绍

  • 1)对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象
  • 2)对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
  • 3)前面我们克隆羊就是浅拷贝
  • 4)浅拷贝是使用默认的 clone 方法来实现:sheep=(Sheep)super.clone();

4.2 深拷贝基本介绍

  • 1)复制对象的所有基本数据类型的成员变量值
  • 2)为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝
  • 3)深拷贝实现方式 1:重写 clone 方法来实现深拷贝
  • 4)深拷贝实现方式 2:通过对象序列化实现深拷贝
package com.zhuangxiaoyan.designpattern.clonemodel;import org.junit.Test;
import java.io.*;class DeepClonableTarget implements Serializable, Cloneable {private String cloneName;private String cloneClass;public DeepClonableTarget(String cloneName, String cloneClass) {this.cloneName = cloneName;this.cloneClass = cloneClass;}public String getCloneName() {return cloneName;}public void setCloneName(String cloneName) {this.cloneName = cloneName;}public String getCloneClass() {return cloneClass;}public void setCloneClass(String cloneClass) {this.cloneClass = cloneClass;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}/*** @description 重写 clone 方法来实现深拷贝* @param: null* @date: 2022/3/27 9:48* @return:* @author: xjl
*/
class DeepPrototype implements Serializable, Cloneable {private String name;private DeepClonableTarget deepClonableTarget;public DeepPrototype() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public DeepClonableTarget getDeepClonableTarget() {return deepClonableTarget;}public void setDeepClonableTarget(DeepClonableTarget deepClonableTarget) {this.deepClonableTarget = deepClonableTarget;}@Overrideprotected Object clone() throws CloneNotSupportedException {//基本数据类型拷贝Object object = super.clone();//引用类型拷贝DeepPrototype deepPrototype = (DeepPrototype) object;deepPrototype.deepClonableTarget = (DeepClonableTarget) deepClonableTarget.clone();return object;}
}/*** @description 深拷贝方式 通过对象序列化实现深拷贝* @param: null* @date: 2022/3/27 9:41* @return:* @author: xjl*/
class DeepPrototypeV2 implements Serializable, Cloneable {private String name;private DeepClonableTarget deepClonableTarget;public DeepPrototypeV2() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public DeepClonableTarget getDeepClonableTarget() {return deepClonableTarget;}public void setDeepClonableTarget(DeepClonableTarget deepClonableTarget) {this.deepClonableTarget = deepClonableTarget;}/*** @description 通过对象序列化实现深拷贝* @param:* @date: 2022/3/27 9:55* @return: com.zhuangxiaoyan.designpattern.clonemodel.DeepPrototype* @author: xjl*/public DeepPrototypeV2 deepClone() {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);return (DeepPrototypeV2) ois.readObject();} catch (Exception e) {e.printStackTrace();return null;} finally {try {if (ois != null) {ois.close();}if (bis != null) {bis.close();}if (oos != null) {oos.close();}if (bos != null) {bos.close();}} catch (IOException e) {e.printStackTrace();}}}
}/*** @Classname DeepTestDemo* @Description* @Date 2022/3/27 9:38* @Created by xjl*/
public class DeepTestDemo {@Testpublic void testv1() throws CloneNotSupportedException {DeepPrototype prototype = new DeepPrototype();prototype.setName("庄小焱");prototype.setDeepClonableTarget(new DeepClonableTarget("及时雨", "及时雨的类"));DeepPrototype clone1 = (DeepPrototype) prototype.clone();DeepPrototype clone2 = (DeepPrototype) prototype.clone();DeepPrototype clone3 = (DeepPrototype) prototype.clone();DeepPrototype clone4 = (DeepPrototype) prototype.clone();DeepPrototype clone5 = (DeepPrototype) prototype.clone();System.out.println(prototype.getName() + ", " + prototype.getDeepClonableTarget().hashCode()); // 庄小焱, 1554874502System.out.println(clone1.getName() + ", " + clone1.getDeepClonableTarget().hashCode()); // 庄小焱, 1846274136System.out.println(clone2.getName() + ", " + clone2.getDeepClonableTarget().hashCode()); // 庄小焱, 1639705018System.out.println(clone3.getName() + ", " + clone3.getDeepClonableTarget().hashCode()); // 庄小焱, 1627674070System.out.println(clone4.getName() + ", " + clone4.getDeepClonableTarget().hashCode()); // 庄小焱, 1360875712System.out.println(clone5.getName() + ", " + clone5.getDeepClonableTarget().hashCode()); // 庄小焱, 1625635731}@Testpublic void testv2() throws CloneNotSupportedException {DeepPrototypeV2 prototypev2 = new DeepPrototypeV2();prototypev2.setName("庄小焱");prototypev2.setDeepClonableTarget(new DeepClonableTarget("zhuangxiaoyan", "yatou"));DeepPrototypeV2 clone1 = prototypev2.deepClone();DeepPrototypeV2 clone2 = prototypev2.deepClone();DeepPrototypeV2 clone3 = prototypev2.deepClone();DeepPrototypeV2 clone4 = prototypev2.deepClone();DeepPrototypeV2 clone5 = prototypev2.deepClone();System.out.println(prototypev2.getName() + ", " + prototypev2.getDeepClonableTarget().hashCode()); // 庄小焱,644117698System.out.println(clone1.getName() + ", " + clone1.getDeepClonableTarget().hashCode());           // 庄小焱, 317574433System.out.println(clone2.getName() + ", " + clone2.getDeepClonableTarget().hashCode());           // 庄小焱, 885284298System.out.println(clone3.getName() + ", " + clone3.getDeepClonableTarget().hashCode());           // 庄小焱, 1389133897System.out.println(clone4.getName() + ", " + clone4.getDeepClonableTarget().hashCode());           // 庄小焱, 1534030866System.out.println(clone5.getName() + ", " + clone5.getDeepClonableTarget().hashCode());           // 庄小焱, 664223387}
}

方式 1 和方式 2 对比

  • 在对象引用类型的成员属性较少时,方式 1 简单;在对象引用类型的成员属性较多时,方式 2 简单
  • 在对象引用类型的成员属性经常发生变化时,方式 1 需要同步修改,方式 2 不用修改
  • 推荐使用方式 2:耦合性低、可维护性强、扩展性高

注意事项和细节

  • 1)优点:创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
  • 2)优点:不用重新初始化对象,而是动态地获得对象运行时的状态
  • 3)优点:如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
  • 4)缺点:在实现深克隆的时候可能需要比较复杂的代码
  • 5)缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了OCP 原则,这点请同学们注意。

博文参考

软件设计模式——原型模式相关推荐

  1. 软件设计模式—命令模式

    前篇--软件设计模式-基础 前篇--软件设计模式-三种工厂模式 前篇--软件设计模式-装饰者模式 前篇--软件设计模式-单例模式 前篇--软件设计模式-原型模式 命令模式是对象行为型模式 目录 1. ...

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

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

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

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

  4. 设计模式 原型模式_原型设计模式:创建另一个小车

    设计模式 原型模式 创建对象确实是一个耗时的过程,也是一件昂贵的事情. 因此,我们现在正冒险节省时间和金钱. 我们该怎么做? 克隆奇迹多莉 有人记得多莉吗? 是的,是绵羊,是第一个被克隆的哺乳动物. ...

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

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

  6. 第六章 Caché 设计模式 原型模式

    文章目录 第六章 Caché 设计模式 原型模式 定义 使用场景 优点 结构图 描述 示例 初级写法 缺点 中级写法 缺点 高级写法 (浅复制) 浅复制 深复制 完整示例 简历类(复制类) 对象类(工 ...

  7. C++设计模式——原型模式(Prototype Pattern)

    C++设计模式--原型模式(Prototype Pattern) 微信公众号:幼儿园的学霸 目录 文章目录 C++设计模式--原型模式(Prototype Pattern) 目录 定义 代码示例 普通 ...

  8. c++设计模式--原型模式(proto pattern)

    一.原理讲解 原型模式其实就是对类对象某个时刻的状态进行备份或者拷贝下来.比如该类的对象进行一系列赋值操作,然后需要保存某个瞬时状态,则用原型模式克隆下来.其中类对象某个瞬时状态用this表示,通过t ...

  9. 设计模式---原型模式(Prototype Pattern)

    在编程中有时候我们会发现,当我们需要一个实例,可是这个实例的创建过程十分复杂,在执行过程中 会消耗大量的时间,同时创建第一个实例和创建第二个时间的初始化信息并未改变.在此种情况下,直接New 一个实例 ...

最新文章

  1. java之==和equals区别
  2. java 基本类型之间的转换
  3. FreeOTP可以用作谷歌认证的替代
  4. 新型机器学习算法:正则化理解
  5. 网络流24题之餐巾计划问题
  6. 利用 Angular Directive 和 @HostBinding 实现输入文本框随着键盘输入自动变色效果
  7. 解决配置Ubuntu中vnc远程显示灰屏
  8. 权限列表(包字典)递归成树状结构
  9. 评分组件(RatingBar)
  10. org.neo4j.kernel.StoreLockException: Store and its lock file has been locked by another process
  11. SSD 下的 MySQL IO 优化
  12. 计算机c盘容易满怎么办,C盘快满了怎么办 如何清理C盘垃圾?
  13. 如果你毕业想进央企, 那就选这些大学, 性价比很高
  14. 一条SQL语句在MySQL中执行过程全解析
  15. 发送邮件被对方服务器退回_国内邮件群发
  16. MATLAB算法实战应用案例精讲-【智能优化算法】黑寡妇算法-BWO(附matlab代码)
  17. IOl数据流中的字节流
  18. 华为harmonyos手机开发者,华为鸿蒙HarmonyOS2.0手机开发者Beta版正式发布
  19. app logo显示不全没有铺满
  20. 谷歌浏览器控制台如何切换中英文

热门文章

  1. Citrix 服务器虚拟化之二十四 桌面虚拟化之Remote PC Access
  2. JAVA 计算当月有多少天
  3. 5G基站用电难题的转机?8大突破案例、25项政策支持!
  4. 一句话木马SQL注入
  5. [SQL]对取出来的数据构造实验组和对照组的方法
  6. 2006-5-7 18:42:00 崔永元逗老外逗出的震撼!!!!绝对经典
  7. 谷歌浏览器插件——Ajax Interceptor,一个用于修改 ajax 请求响应的 chrome 扩展,可以修改ajax请求返回结果,在浏览器上直接mock数据
  8. cpuidle framework in Linux Kernel(2)what's idle state
  9. easyui 根据值查找匹配
  10. php高级教程blog博,贾沦一盒纤斯人博客|PHP高级教程|C  |J