概述
当我们创造一个类的一个实例很复杂,并且需要创建多个这样的类的实例时,如果用new操作符去创建这样的类实例,这会增加类的复杂度和耗费更多的内存空间,因为这样在内存中分配了多个一样的类实例对象,如果采用工厂模式创建的话,随着产品类的不断增加,导致子类数量不断增多,又会增加系统的复杂度。原型模式的思想是:只创建一个类实例对象,如果后面需要更多的类实例,可以通过原来的对象拷贝一份来完成创建,这样在内存中不需要创建多个相同的类实例。
原型类需要具备两个条件
- 实现Cloneable接口(在java虚拟机中,只有实现了这个接口的类才可以被拷贝)
- 重写Object类中的clone方法
浅拷贝和深拷贝
浅拷贝:只拷贝基本数据类型,对于对象会将引用指向同一个。
深拷贝:所有数据都复制一份。
下面看一下浅复制的代码:
package ShallowCopy;
/**
* Created with IntelliJ IDEA.
* User: YEN
* Date: 2016/7/26
* Time: 20:17
*/
public class ShallowCopy {
//名称
public String name;
//数组
public int[] arr = new int[10];
}
package ShallowCopy;
/**
* Created with IntelliJ IDEA.
* User: YEN
* Date: 2016/7/26
* Time: 20:18
*/
//浅复制实例
public class ShallowCopyTest {
public static void main(String[] args) {
//创建对象A
ShallowCopy A=new ShallowCopy();
//给A赋值
A.name="YEN";
for (int i = 0; i < 10; i++) {
A.arr[i]=i;
}
//创建对象B
ShallowCopy B=A;
System.out.println("\n.............修改A前的A...................");
ShowArr(A);
System.out.println("\n.............修改A前的B...................");
ShowArr(B);
//修改A中的数组的值
A.name="yen";
A.arr[0]=100;
System.out.println("\n.............修改A后的A...................");
ShowArr(A);
System.out.println("\n.............修改A后的B...................");
ShowArr(B);
}
public static void ShowArr(ShallowCopy temp){
System.out.println("名称:"+temp.name);
System.out.print("数组:");
for (int i = 0; i <temp.arr.length ; i++) {
System.out.print(temp.arr[i]+" ");
}
}
}
可以看出:当A对象的信息修改后,B信息的也会更着改变,所以他们的数据其实是指向了同一个引用,这显然不是我们想要的。
而深拷贝则是把所有数据都拷贝一分,两个对象互不影响。
利用序列化实现深度克隆
把对象写到流里的过程是序列化(Serialization)过程;而把对象从流中读出来的过程则叫反序列化(Deserialization)过程。应当指出的是,写到流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。
在Java语言里深度克隆一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的拷贝)写到一个流里(序列化),再从流里读回来(反序列化),便可以重建对象。
public class DeepClone {
public Object DeepClone() throws IOException, ClassNotFoundException {
//将对象写到流里
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(this);
//从流中读回来
ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bais);
return ois.readObject();
}
}
下面通过一个例子来说明:
package DeepCopy;
import java.io.*;
/**
* Created with IntelliJ IDEA.
* User: YEN
* Date: 2016/7/26
* Time: 20:46
*/
public class DeepClone implements Cloneable,Serializable {
private String name;
private int age;
//构造函数
DeepClone(){
this.name="YEN";
this.age=20;
}
//通过克隆方法
public Object clone() throws CloneNotSupportedException {
DeepClone temp=(DeepClone)super.clone();
return temp;
}
//通过序列化与反序列化方法
public Object DeepClone() throws IOException, ClassNotFoundException {
//将对象写到流里
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(this);
//从流中读回来
ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bais);
return ois.readObject();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package DeepCopy;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* User: YEN
* Date: 2016/7/26
* Time: 20:58
*/
public class DeepCloneTest {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
DeepClone A=new DeepClone();
DeepClone B= (DeepClone) A.clone();
DeepClone C= (DeepClone) A.DeepClone();
System.out.println("==================修改A前=========================");
System.out.println("A name:"+A.getName());
System.out.println("A age:"+A.getAge());
System.out.println(".........................................");
System.out.println("B name:"+B.getName());
System.out.println("B age:"+B.getAge());
System.out.println(".........................................");
System.out.println("C name:"+C.getName());
System.out.println("C age:"+C.getAge());
A.setName("yen");
A.setAge(19);
System.out.println("==================修改A后=========================");
System.out.println("A name:"+A.getName());
System.out.println("A age:"+A.getAge());
System.out.println(".........................................");
System.out.println("B name:"+B.getName());
System.out.println("B age:"+B.getAge());
System.out.println(".........................................");
System.out.println("C name:"+C.getName());
System.out.println("C age:"+C.getAge());
}
}
原型模式在生成比较复杂对象的环境中比较适用,通过克隆已有对象来实现创建新的对象,节省了时间和空间。