原型模式(Prototype Pattern)

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

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

案例一:传统方式

public class Sheep {private String name;private int age;private String color;//...省略get,set,toString,有参构造
public class Client {public static void main(String[] args) {//传统的方法Sheep sheep = new Sheep("tom", 1, "白色");Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());//....System.out.println(sheep);System.out.println(sheep2);//...}
}

优点

  • 比较好理解, 简单易操作

缺点

  • 在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低
  • 总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活

案例二:原型模式

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

  • 原型模式(Prototype 模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
  • 原型模式是–种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节
  • 工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它
    clone对象实现Cloneable
public class Sheep implements Cloneable {private String name;private int age;private String color;private String address = "蒙古羊";public Sheep friend; //是对象, 克隆是会如何处理//...省略get,set,toString,有参构造//克隆该实例,使用默认的clone方法来完成@Overrideprotected Object clone()  {Sheep sheep = null;try {sheep = (Sheep)super.clone();} catch (Exception e) {System.out.println(e.getMessage());}return sheep;}
}
public class Client {public static void main(String[] args) {System.out.println("原型模式完成对象的创建");// TODO Auto-generated method stubSheep sheep = new Sheep("tom", 1, "白色");sheep.friend = new Sheep("jack", 2, "黑色");Sheep sheep2 = (Sheep)sheep.clone(); //克隆Sheep sheep3 = (Sheep)sheep.clone(); //克隆System.out.println("sheep2 =" + sheep2 + "sheep2.friend=" + sheep2.friend.hashCode());System.out.println("sheep3 =" + sheep3 + "sheep3.friend=" + sheep3.friend.hashCode());}
}

原型模式在Spring框架中源码分析

Spring中原型bean的创建,就是原型模式的应用

 <!-- 这里我们的 scope="prototype" 即 原型模式来创建 --><!-- 这里我们的 scope="prototype" 即 原型模式来创建 --><beans><bean id="monster" class="com.jsxl.spring.bean.Monster" scope="prototype"/><bean id="friend" class="com.jsxl.spring.bean.Friend" scope="prototype"/></beans>
public class Monster {private Integer id = 10 ;private String nickname = "牛魔王";private String skill = "芭蕉扇";private Friend friend =new Friend(1,"孙悟空");//...省略get,set,toString,有参构造
}
public class Friend {private Integer;private String nickname;//...省略get,set,toString,有参构造
 <!-- 这里我们的 scope="prototype" 即 原型模式来创建 --><beans><bean id="monster" class="com.jsxl.spring.bean.Monster" scope="prototype"/><bean id="friend" class="com.jsxl.spring.bean.Friend" scope="prototype"/></beans>
public class ProtoType {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");// 获取monster[通过id获取monster]Monster monster = (Monster)applicationContext.getBean("monster");monster.getFriend().hashCode();System.out.println("monster" + monster +"hashCode"+monster.getFriend().hashCode()); Monster monster2 = (Monster)applicationContext.getBean("monster");System.out.println("monster2" + monster2+"hashCode"+monster2.getFriend().hashCode()); System.out.println(monster == monster2); // false}
}


通过debug找到源码判断

// Create bean instance.if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {@Overridepublic Object getObject() throws BeansException {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}

深入讨论浅拷贝和深拷贝

浅拷贝

  • 对于数据类型是基本数据类型及string类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。“string”属于Java中的字符串类型,也是一个引用类型,并不属于基本的数据类型。
  • 对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值

浅拷贝是使用默认的clone()方法来实现

sheep = (Sheep) super.clone();

深拷贝

  • 复制对象的所有基本数据类型的成员变量值
  • 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝
  • 深拷贝实现方式1:重写clone方法来实现深拷贝
  • 深拷贝实现方式2:通过对象序列化实现深拷贝(推荐)
    被引用对象继承Cloneable重新clone()方法
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;}//因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class DeepProtoType implements Serializable, Cloneable{public String name; //String 属性public DeepCloneableTarget deepCloneableTarget;// 引用类型public DeepProtoType() {super();}//深拷贝 - 方式 1 使用clone 方法@Overrideprotected Object clone() throws CloneNotSupportedException {Object deep = null;//这里完成对基本数据类型(属性)和String的克隆deep = super.clone(); //对引用类型的属性,进行单独处理DeepProtoType deepProtoType = (DeepProtoType)deep;deepProtoType.deepCloneableTarget  = (DeepCloneableTarget)deepCloneableTarget.clone();// TODO Auto-generated method stubreturn 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) {// TODO: handle exceptione.printStackTrace();return null;} finally {//关闭流try {bos.close();oos.close();bis.close();ois.close();} catch (Exception e2) {System.out.println(e2.getMessage());}}}
}
public class Client {public static void main(String[] args) throws Exception {DeepProtoType p = new DeepProtoType();p.name = "张三";p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");//方式1 完成深拷贝
//      DeepProtoType p2 = (DeepProtoType) p.clone();
//      System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
//      System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());//方式2 完成深拷贝DeepProtoType p2 = (DeepProtoType) p.deepClone();System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());}
}

总结

  • 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
  • 不用重新初始化对象,而是动态地获得对象运行时的状态
  • 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码

在实现深克隆的时候可能需要比较复杂的代码

  • 缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了ocp原则

原型模式(Prototype Pattern)相关推荐

  1. 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)

    [索引页] [源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:webabcd 介绍 用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象. ...

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

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

  3. 极速理解设计模式系列:4.原型模式(Prototype Pattern)

    四个角色:抽象原型角色(Prototype).具体原型角色(ConcretePrototype).原型管理器角色(PrototypeManager).客户端角色(Client) 抽象原型角色(Prot ...

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

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

  5. 设计模式(23):创建型-原型模式(Prototype)

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...

  6. 原型模式(ProtoType) - Java里的对象复制

    一, 引用的复制和对象复制. 在编程中, 我们有时会用两个引用指向同一个对象. 例如: ArrayList a = new ArrayLIst(); ArrayList b = a; 看起来好像有a, ...

  7. 原型模式-prototype

    一.什么是原型模式 Prototype模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例.使用Prototype模式创建的实例,具有与原型一样的数据. 二.原型模式的特点 1.由原型对 ...

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

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

  9. 设计模式(三)原型模式 Prototype

    原型模式 原型模式概念 适用场景 简单克隆 浅克隆 深克隆 破坏单例 开源工具 总结 原型模式概念 原型模式(Prototype Pattern)是指原型实例指定创建对象的 种类,并且通过拷贝这些原型 ...

最新文章

  1. html指定表格行列书,js动态生成指定行数的表格
  2. Java并发编程——线程池的使用
  3. 为IT基础设施提供云端储存,云数据存储公司Nasuni获3800万美元股权融资
  4. [C#] 接收和发送UDP数据
  5. 最长非下降子序列(O(nlogn))(offer收割)
  6. Nginx(二):安装、配置、常用命令
  7. staf工作笔记-使用stax并行处理获取其他主机操作系统信息
  8. IP地址专题二:子网掩码入门
  9. 使用网络调试助手 MQTT接入阿里云物联网平台,逐字节讲解,适用单片机/ESP8266接入阿里云
  10. html5表单提交json数据库,使用html5的FormData对象,通过 Ajax表单异步提交文件数据...
  11. tensorflow支持python3.7吗_前端开发行业真的会被AI取代吗?
  12. vmware player 虚拟机下windows系统安装vmware tools
  13. 【配置管理】配置审核-物理配置审核-功能配置审核-配置管理审核
  14. systrace打印
  15. 什么是驻点和拐点_驻点、极值点、拐点、鞍点的区别与联系
  16. Boni Satani谈迁移遗留系统的5个原因
  17. 傅里叶变换的性质及证明(CTFT)
  18. 编程c语言counter,c语言中计算平均分时,计数器(counter)的初始化
  19. 2020年7月19日训练总结
  20. wordpress主题框架之Thematic介绍

热门文章

  1. 入职新公司第一周的感受
  2. 桥接模式(Bridge模式)详解
  3. Microsoft Word 2019 for mac(word mac)
  4. 我从没像今天这样渴望过太阳
  5. wscript.shell使用
  6. C++:乘法运算符和取模运算符
  7. 好看的导航主页html,推荐|各种漂亮的网页导航,让浏览器靓起来
  8. 程序员漫漫回乡路--我以前的一些想法
  9. 新思路计算机等级考试50套,新思路计算机一级选择题50套(含答案)讲解.doc
  10. 国产化网管软件的开发与应用