1.思考问题

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

按照传统的思路来,我们可能会按照下面的方式去写。

那么这种写法的优缺点自然而然就出来了:

  • 优点是比较好理解,简单易操作。
  • 缺点是在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低。总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活。
  • 改进的思路分析:Java中Object类是所有类的根类,Object类提供了一个 clone()方法,该方法可以将一个Java对象复制一份,但是需要实现clone的Java类必须要实现一个接口Cloneable,该接口表示该类能够复制且具有复制的能力  =>  原型模式。

2.什么是原型模式?

  1. 原型模式(Prototype模式)是指:  用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。
  2. 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。
  3. 工作原理是:  通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即对象.clone()。

原型模式相关的类图如下:


3.克隆羊多莉案例代码(浅拷贝)

这里由于我是新建的普通Java项目,并不是maven项目,所以没法加lombok依赖。那么这里的构造器、setter/getter方法显得这个类的篇幅比较长。。。

package com.szh.prototype.shallowclone;public class Sheep implements Cloneable {private String name;private Integer age;private String color;private Sheep friend;public Sheep(String name, Integer age, String color) {this.name = name;this.age = age;this.color = color;}public Sheep(String name, Integer age, String color, Sheep friend) {this.name = name;this.age = age;this.color = color;this.friend = friend;}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 getFriend() {return friend;}public void setFriend(Sheep friend) {this.friend = friend;}@Overridepublic String toString() {return "Sheep{" +"name='" + name + '\'' +", age=" + age +", color='" + color + '\'' +", friend=" + friend +'}';}//克隆该实例,使用默认的clone方法来完成@Overrideprotected Object clone()  {Sheep sheep = null;try {sheep = (Sheep) super.clone();} catch (CloneNotSupportedException e) {System.out.println(e.getMessage());}return sheep;}
}
package com.szh.prototype.shallowclone;public class MainTest {public static void main(String[] args) {Sheep sheep = new Sheep("多莉",5,"黑白相间",new Sheep("喜羊羊",1,"白色"));Sheep sheep2 = (Sheep) sheep.clone();Sheep sheep3 = (Sheep) sheep.clone();Sheep sheep4 = (Sheep) sheep.clone();Sheep sheep5 = (Sheep) sheep.clone();System.out.println(sheep + "  sheep.friend.hashCode = " + sheep.getFriend().hashCode());System.out.println(sheep2 + "  sheep2.friend.hashCode = " + sheep2.getFriend().hashCode());System.out.println(sheep3 + "  sheep3.friend.hashCode = " + sheep3.getFriend().hashCode());System.out.println(sheep4 + "  sheep4.friend.hashCode = " + sheep4.getFriend().hashCode());System.out.println(sheep5 + "  sheep5.friend.hashCode = " + sheep5.getFriend().hashCode());}
}

从上面的运行结果中可以看到,Sheep类中的前三个成员属性都可以成功的拷贝,但是最后一个friend,它表示羊的朋友(也是Sheep类型,就是引用类型了)。而当我们拷贝完成之后,应该来说都是不一样的新的对象,但是它们中的friend属性的hashCode居然是一样的!!!    这里我们就要来聊一聊深拷贝和浅拷贝了。

浅拷贝:

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

深拷贝:

  • 复制对象的所有基本数据类型的成员变量值。
  • 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝。
  • 深拷贝实现方式1:  重写clone方法来实现深拷贝。
  • 深拷贝实现方式2:  通过对象序列化实现深拷贝(推荐)。

4.深拷贝代码案例

package com.szh.prototype.deepclone;import java.io.Serializable;public class DeepCloneableTarget implements Serializable, Cloneable {private static final long serialVersionUID = 1L;private String cloneName;private String cloneClass;public DeepCloneableTarget(String cloneName, String cloneClass) {this.cloneName = cloneName;this.cloneClass = cloneClass;}@Overridepublic String toString() {return "DeepCloneableTarget{" +"cloneName='" + cloneName + '\'' +", cloneClass='" + cloneClass + '\'' +'}';}//因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
package com.szh.prototype.deepclone;import java.io.*;public class DeepPrototype implements Serializable, Cloneable {public String name; //String 属性public DeepCloneableTarget deepCloneableTarget;// 引用类型public DeepPrototype() {super();}@Overridepublic String toString() {return "DeepPrototype{" +"name='" + name + '\'' +", deepCloneableTarget=" + deepCloneableTarget +'}';}//深拷贝 - 方式 1 使用clone 方法@Overrideprotected Object clone() throws CloneNotSupportedException {Object deep = null;deep = super.clone();DeepPrototype deepPrototype = (DeepPrototype) deep;deepPrototype.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();return deepPrototype;}//深拷贝 - 方式2 通过对象的序列化实现 (推荐)public Object 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);DeepPrototype copyObj = (DeepPrototype) ois.readObject();return copyObj;} catch (Exception e) {e.printStackTrace();return null;} finally {//关闭流try {ois.close();bis.close();oos.close();bos.close();} catch (Exception e2) {System.out.println(e2.getMessage());}}}
}
package com.szh.prototype.deepclone;public class MainTest {public static void main(String[] args) throws Exception {DeepPrototype prototype = new DeepPrototype();prototype.name = "张起灵";prototype.deepCloneableTarget = new DeepCloneableTarget("小哥","闷油瓶");//方式1 完成深拷贝DeepPrototype prototype2 = (DeepPrototype) prototype.clone();System.out.println("方式1 完成深拷贝");System.out.println("prototype.name = " + prototype.name + ", prototype.deepCloneableTarget = " + prototype.deepCloneableTarget);System.out.println("prototype.deepCloneableTarget.hashCode = " + prototype.deepCloneableTarget.hashCode());System.out.println("-------------------------------------------------------");System.out.println("prototype2.name = " + prototype2.name + ", prototype2.deepCloneableTarget = " + prototype2.deepCloneableTarget);System.out.println("prototype2.deepCloneableTarget.hashCode = " + prototype2.deepCloneableTarget.hashCode());System.out.println("==============================================================================");//方式2 完成深拷贝DeepPrototype prototype3 = (DeepPrototype) prototype.deepClone();System.out.println("方式2 完成深拷贝");System.out.println("prototype.name = " + prototype.name + ", prototype.deepCloneableTarget = " + prototype.deepCloneableTarget);System.out.println("prototype.deepCloneableTarget.hashCode = " + prototype.deepCloneableTarget.hashCode());System.out.println("-------------------------------------------------------");System.out.println("prototype3.name = " + prototype3.name + ", prototype3.deepCloneableTarget = " + prototype3.deepCloneableTarget);System.out.println("prototype3.deepCloneableTarget.hashCode = " + prototype3.deepCloneableTarget.hashCode());}
}


5.原型模式总结

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

创建型设计模式——原型模式相关推荐

  1. 创建型设计模式-----原型模式(浅克隆、深克隆)

    目录 简介 为什么用克隆 浅克隆 深克隆 序列化实现深拷贝 应用场景 今天讲创建型设计模式中的原型模式,大家可以从标题中略微猜测一下,这个原型模式是个什么东东. 简介 定义:用原型实例创建对象的种类, ...

  2. 创建型设计模式-原型模式

    文章目录 原型模式 一.浅拷贝 二.深拷贝 2.1 序列化与反序列化进行深拷贝 2.2 在原型类的 clone 方法中单独处理引用对象 原型模式 原型模式(Prototype Pattern)是用于创 ...

  3. Java设计模式之创建型:原型模式

    一.什么是原型模式: 原型模式主要用于对象的创建,使用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.UML类图如下: 原型模式的核心是就是原型类 Prototype,Prototype ...

  4. Java创建型设计模式——建造者模式

    文章目录 1.0概念理解 2.0编码理解 2.1编码说明 2.2编码实现 五种创建型设计模式:工厂方法模式.抽象工厂模式.建造者模式.原型模式.单例模式 1.0概念理解 ​ ​ 一句话理解:建造者模式 ...

  5. (创建型)设计模式——工厂模式(factory)

    ps:在以下讲述工厂模式中,模仿的场景如下:我们需要生产Car,建立相对应的CarFactory.使用CarFactory工厂来生产Car,并且可以在生产过程中进行一些处理.类图和代码如下. 1.Mo ...

  6. 创建型设计模式——建造者模式

    1.提出问题 假如说,我们需要建房子:这一过程为打桩.砌墙.封顶.房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不要相同的.3)请编写程序,完成需求. 传统的想法应该就是下 ...

  7. 创建型设计模模式---原型模式

    设计模式 序号 内容 链接地址 1 设计模式七大原则 https://blog.csdn.net/qq_39668819/article/details/115390615 2 创建型设计模式–工厂模 ...

  8. 行为型设计模式---模板方法模式

    设计模式 序号 内容 链接地址 1 设计模式七大原则 https://blog.csdn.net/qq_39668819/article/details/115390615 2 创建型设计模式–工厂模 ...

  9. 创建型设计模模式---建造者模式

    设计模式 序号 内容 链接地址 1 设计模式七大原则 https://blog.csdn.net/qq_39668819/article/details/115390615 2 创建型设计模式–工厂模 ...

最新文章

  1. Block相关内容梳理
  2. “面试不败计划”:面试题基础三
  3. 2009年3月全国计算机等级考试二级vfp笔试,2009年3月全国计算机等级考试二级VFP笔试试题及答案.doc...
  4. 大数据的起步:初学者
  5. mp3 pcm java_Java mp3文件转pcm文件
  6. E. Pattern Matching(题意理解+拓扑排序)
  7. 【mysql的设计与优化专题(6)】mysql索引攻略
  8. 国外一些知名ASP.Net开源CMS系统
  9. 2020大学生就业报告:IT行业人才缺口巨大,好就业
  10. 软件工程导论 第五版 张海藩 编著 总结
  11. Spark中repartition和coalesce的用法
  12. 毫无破绽的:Access denied for user ‘root‘@‘%‘ (using password: YES)
  13. kali系统升级(包含软件信息、所有软件、整个系统)
  14. 视频流编码格式(四字符码)对照表
  15. 部署Microsoft LAPS分步指南
  16. 在 Visual Studio 2010 中创建 ASP.NET Web 项目
  17. openjpeg:jpeg2000(j2k)图像内存解压缩(解码)
  18. python 使用随笔
  19. 关于微信自动回复机器人
  20. 高中教资信息技术Flash动画软件分享

热门文章

  1. 【蓝桥杯】【星系炸弹】
  2. 使用pytorch搭建AlexNet并训练花分类数据集
  3. 【方法】pyautogui入门学习(python自动脚本)
  4. 全新支付方式你用过几种?
  5. 5G给医疗行业带来哪些变化?
  6. 聊城大数据中心基本建成
  7. YOLOv2 沉思录
  8. iTunes Connect新创建 App
  9. TFS 掩蔽或取消掩蔽工作区中的文件夹
  10. Python+Vue计算机毕业设计一品萫茶馆管理系统的设计与实现69dcm(源码+程序+LW+部署)