如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型设计模式(Prototype Design Pattern),简称原型模式。
原型模式的两种实现方式
浅拷贝:当拷贝对象包含基本数据类型(如int、long)或者不可变的对象(如字符串、基本类型的包装类)时,会直接将这些属性复制到新的对象中。而原型对象中的引用对象会把内存中的地址复制给克隆对象。此时,两个对象共享了一个私有变量,你改我改大家都能改。
深拷贝:不管原型对象属性是简单数据类型还是引用对象类型都会完全的复制一份到新的对象中。两个对象之间互不影响。
那原型模式该如何实现深拷贝呢?
@Datapublic class ConcretePrototype implements Serializable, Cloneable {private Long num;private ArraylisteObject> list;@Overridepublic ConcretePrototype clone() {ConcretePrototype concretePnototype = null;try {// 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVH里面。所以利用这个特性可以实现对象的深找贝ByteArrayOutputStream bas = new ByteArrayOutputStrean();ObjectOutputStream oos = new ObjectOutputStream(bas);oos.mrite0bject(this);// 再将溃序列化成对象ByteArrayInputStream bis = new ByteArrayInputStream(bas.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);concnetePrototype = (ConcretePrototype) ois.readobject(0);} catch (Exception e) {e.printStackTrace();}return concretePrototype;}}
原理:
序列化需要使用的两个类:ObjectOutputStream类用于序列化、ObjectInputStream用于反序列化。
首先使用ObjectOutputStream类将对象写入到ByteArrayOutputStream中,然后将ByteArrayOutputStream中的字节序列递交给ByteArrayInputStream,最后使用ObjectInputStream将ByteArrayInputStream中的字节序列重新反转为一个对象。
注意:深拷贝比浅拷贝需要更多的资源,按照实际场景选择。现在已经有很多针对浅深拷贝的工具类
深拷贝:SerializationUtils
浅拷贝:BeanUtils
原型模式的优点
1、原型模式是在内存中进行二进制流的拷贝,要比直接new一个对象性能好,特别是在一个循环体内创建大量对象时。
2、原型模式可以简化对象创建的过程,可以直接拷贝现有的原型实例的值,实现对象复用。
适用场景
1、性能优化场景:类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
2、安全访问场景:当某个对象对外可能是只读的,为了防止外部对这个只读对象的修改,通常可以通过返回一个对象拷贝的形式实现只读的限制。
3、一个对象多个修改者的场景:一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。