原型模式
(用原型实例指定创建对象的种类, 并且通过拷贝这些原型创建新的对象。
原型模式实际上就是实现 Cloneable 接口,重写 clone()方法。
使用原型模式的优点:
● 性能优良 原型模式是在内存二进制流的拷贝,要比直接 new 一个对象性能好很多,特别是 要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
● 逃避构造函数的约束 这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的
使用场景:
● 资源优化场景 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
● 性能和安全要求的场景 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模 式。
● 一个对象多个修改者的场景 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以 考虑使用原型模式拷贝多个对象供调用者使用。
浅拷贝和深拷贝:
浅拷贝:Object 类提供的方法 clone 只是拷贝本对象,其对象内部的数组、引用 对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝,其 他的原始类型比如 int、long、char、string(当做是原始类型)等都会被拷贝。 注意: 使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是 类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个 原始类型或不可变对象。
深拷贝:对私有的类变量进行独立的拷贝 如:thing.arrayList = (ArrayList)this.arrayList.clone();
代码:
1. 实体对象
public class NewPrototype implements Cloneable {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
private Prototype prototype;
public Prototype getPrototype() {
return prototype;
}
public void setPrototype(Prototype prototype) {
this.prototype = prototype;
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
/**
* 深复制
*
* @author WHM
*
*/
public class NewPrototypes implements Cloneable {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
private Prototypes prototype;
public Prototypes getPrototype() {
return prototype;
}
public void setPrototype(Prototypes prototype) {
this.prototype = prototype;
}
public Object clone() {
NewPrototypes ret = null;
try {
ret = (NewPrototypes) super.clone();
ret.prototype = (Prototypes) this.prototype.clone();
return ret;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
public class Prototype {
//引用类型
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Prototypes implements Cloneable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
import java.io.Serializable;
public class PrototypeSe implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 序列化实现深复制
*
* @author WHM
*
*/
public class NewPrototypeSe implements Serializable {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
private PrototypeSe prototype;
public PrototypeSe getPrototype() {
return prototype;
}
public void setPrototype(PrototypeSe prototype) {
this.prototype = prototype;
}
public Object deepClone() {
ByteArrayOutputStream bo = null;
ObjectOutputStream oo = null;
ByteArrayInputStream bi = null;
ObjectInputStream oi = null;
try {
bo = new ByteArrayOutputStream();
oo = new ObjectOutputStream(bo);
oo.writeObject(this);
bi = new ByteArrayInputStream(bo.toByteArray());
oi = new ObjectInputStream(bi);
return oi.readObject();
} catch (IOException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} finally {
try {
if(bo != null) {
bo.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(oo != null) {
oo.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(bi != null) {
bi.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(oi != null) {
oi.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2 验证
package pattern.prototype;
import java.io.IOException;
/**
* 原型模式(Prototype pattern)是指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。原型模式主要适用于以下:
(1)类初始化消耗资源较多;
(2)使用new 生成一个对象需要非常繁琐的过程(数据准备访问权限等);
(3)构造函数比较复杂;
(4)在循环体中产生大量对象;
在spring中用到的原型模式有:scope="prototype" ,还有常用的JSON.parseObject()也是一种原型模式
* @author WHM
*
* 2.在Java中对象的克隆有深克隆和浅克隆之分。
* 有这种区分的原因是Java中分为基本数据类型和引用数据类型
* ,对于不同的数据类型在内存中的存储的区域是不同的。基本数据类型存储在栈中,引用数据类型存储在堆中。
*
* 2.1浅克隆
只复制基本类型的数据,引用类型的数据只复制了引用的地址,引用的对象并没有复制,在新的对象中修改引用类型的数据会影响原对象中的引用
2.2复制后的对象与原对象之间完全不会影响。
*/
public class TMain {
public static void main(String[] args) throws Exception {
/**
* 浅复制
*/
Prototype pro = new Prototype(); pro.setName("original object"); NewPrototype
newObj = new NewPrototype(); newObj.setId("test1"); newObj.setPrototype(pro);
NewPrototype copyObj = (NewPrototype)newObj.clone();
copyObj.setId("testCopy"); //String对象值会变化
copyObj.getPrototype().setName("changed object");
System.out.println("original object id:" + newObj.getId());
System.out.println("original object name:" +
newObj.getPrototype().getName());
System.out.println("cloned object id:" + copyObj.getId());
System.out.println("cloned object name:" + copyObj.getPrototype().getName());
/**
* 深复制
*/
// Prototypes pro = new Prototypes(); pro.setName("original object");
// NewPrototypes newObj = new NewPrototypes(); newObj.setId("test1");
// newObj.setPrototype(pro);
//
// NewPrototypes copyObj = (NewPrototypes)newObj.clone();
// copyObj.setId("testCopy"); copyObj.getPrototype().setName("changed object");
//
// System.out.println("original object id:" + newObj.getId());
// System.out.println("original object name:" +
// newObj.getPrototype().getName()); //2个全新的对象
// System.out.println("cloned object id:" + copyObj.getId());
// System.out.println("cloned object name:" + copyObj.getPrototype().getName());
//
/**
* 3.深复制by Serializable
*/
// TODO Auto-generated method stub
PrototypeSe po = new PrototypeSe();
po.setName("test1");
NewPrototypeSe se = new NewPrototypeSe();
se.setPrototype(po);
NewPrototypeSe deepClone = (NewPrototypeSe)se.deepClone();
deepClone.getPrototype().setName("test2");
System.out.println("original name:" + se.getPrototype().getName());
System.out.println("cloned name:" + deepClone.getPrototype().getName());
}
}
3. 结果