创建型之原型模式
原型模式(Prototype Pattern)
不需要经过构造函数创建实例,直接在内存中拷贝对象实例,常用于为了创建重复的对象,又要保证较高性能的场景。
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点:如果复制的对象 里面又有引用其他对象,然后引用的其他对象再有其他对象的引用(有很多层),需要考虑以下问题:1、复制需要深入多少层。2、如何避免出现循环引用的问题
使用场景: 1、资源优化场景,对于一个已存在内存中的类实例,需要创建多个实例提供给其他对象访问,而且各个调用者可能都需要修改其值时,但是类初始化需要消化非常多的资源,这个资源包括硬件资源、非常繁琐的数据准备或访问权限等,可以考虑使用原型模式拷贝多个对象供调用者使用。
java最常见的原型模式实现就是深拷贝与浅拷贝。
浅拷贝
在内存层面对一个对象进行拷贝,对象有着原始对象基本类型数据的一份精确拷贝,及引用类型的内存地址拷贝。即如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址。因此,如果其中一个对象改变了这个地址,就会影响到另一个对象。
实现方式:重写Clone方法
public class ShallowClone implements Cloneable {
public int a; // 基本类型
public int[]b; // 非基本类型
// 重写Object.clone()方法,并把protected改为public
@Override
public Objectclone(){
ShadowClone sc =null;
try{
sc = (ShallowClone)super.clone();
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return sc;
}
}
深拷贝
在内存层面对一个对象进行拷贝,对象有着原始对象基本类型数据的一份精确拷贝,及引用类型的内存地址指向的内存数据。即如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址指向的内存数据。因此,如果其中一个对象改变了这个地址,不会影响到另一个对象。
实现方式:
1、重写Clone方法
class Bottle implements Cloneable {
public Wine wn;
public Bottle(Wine wn){
this.wn = wn;
}
// 覆写clone()方法
@Override
protected Object clone() throws CloneNotSupportedException{
Bottle newBtl = (Bottle)super.clone();
newBtl.wn = (Wine) wn.clone();
return newBtl;
}
}
class Wine implements Cloneable {
int degree;
public int getDegree() {
return degree;
}
public void setDegree(int degree){
this.degree = degree;
}
// 覆写clone()方法
@Override
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
2、采用序列化方式,例如serializable、 Parcelable、ProtoBuf等
class DeepPerson implements Serializable {
private int a;
private int[] b;
public DeepPerson(){
}
public DeepPerson(int a, int[] b){
this.a = a;
this.b = b;
}
public int getA(){
return a;
}
public void setA(int a){
this.a = a;
}
public int[] getB(){
return b;
}
public void setB(int[] b){
this.b = b;
}
}
public static void main(String[] args) throws CloneNotSupportedException{
DeepPerson dc1 = new DeepPerson();
// 对dc1赋值
dc1.setA(100);
dc1.setB(new int[]{ 1000 });
System.out.println("克隆前dc1: a=" + dc1.getA()+"b[0]=" + dc1.getB()[0]);
DeepPerson dc2 = (DeepPerson) deepClone(dc1);
// 对c2进行修改
dc2.setA(50);
int[] a = dc2.getB();
a[0] =500;
System.out.println("克隆后dc1: a=" + dc1.getA()+"b[0]=" + dc1.getB()[0]);
System.out.println("克隆后dc2: a=" + dc2.getA()+"b[0]=" + dc2.getB()[0]);
}
public static Object deepClone(Objectobject){
Object o=null;
try{
if (object !=null){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
o = ois.readObject();
ois.close();
}
} catch (IOException e){
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return o;
}
}