简介
原型模式是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。
目的:通过复制一个已有实例可以提高新实例的创建效率,减少构造函数的调用次数。
缺点:需要对每一个类加入clone函数,违背了ocp原则。
实现步骤
- 实现cloneable接口。调用对象clone函数时会检查是否实现cloneable接口,没有实现会报错。
- 重写clone方法。
原型模式有两种拷贝方式:浅拷贝、深拷贝。
浅拷贝
父类(Object)的clone方法默认为浅拷贝,拷贝时值变量复制值,引用变量复制地址。
class DeepTest{
}
public class Person implements Cloneable{
private String name;
private Integer age;
public DeepTarget deepTarget;//引用变量
public Person(String name, Integer age,DeepTarget deepTarget) {
this.name = name;
this.age = age;
this.deepTarget=deepTarget;
}
@Override
protected Object clone() throws CloneNotSupportedException {
//调用父类的拷贝
return super.clone();
}
}
测试函数:
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person("a",1,new DeepTarget());
System.out.println(person.deepTarget.hashCode());
for (int i = 0; i < 10; i++) {
Person clone = (Person)person.clone();
System.out.println(clone.deepTarget.hashCode());
}
}
可以得出结果:通过clone创建的10个类中deepTest都为同一个,即父类的clone为浅拷贝。
深拷贝
方法1:
需要深拷贝的目标对象重写clone方法、实现Cloneable接口。
在clone方法中单独对需要深拷贝的对象进行处理。
class DeepTarget implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Person implements Cloneable{
private String name;
private Integer age;
public DeepTarget deepTarget;
public Person(String name, Integer age,DeepTarget deepTarget) {
this.name = name;
this.age = age;
this.deepTarget=deepTarget;
}
@Override
protected Object clone() throws CloneNotSupportedException {
//完全基本数据类型的克隆
Person p = (Person) super.clone();
//单独处理DeepTarget,使用新的clone对象
p.deepTarget= (DeepTarget) deepTarget.clone();
return p;
}
}
方法2:
经过序列化获取新对象。
class DeepTarget implements Serializable {
}
public class Person implements Cloneable,Serializable{
private String name;
private Integer age;
public DeepTarget deepTarget;
public Person(String name, Integer age,DeepTarget deepTarget) {
this.name = name;
this.age = age;
this.deepTarget=deepTarget;
}
@Override
protected Object clone() throws CloneNotSupportedException {
ObjectOutputStream oos =null;
ByteArrayOutputStream bos=null;
ObjectInputStream ois=null;
ByteArrayInputStream bis=null;
try {
bos=new ByteArrayOutputStream();
oos=new ObjectOutputStream(bos);
oos.writeObject(this);//将对象写入bos的缓存中
bis=new ByteArrayInputStream(bos.toByteArray());
ois=new ObjectInputStream(bis);
return ois.readObject();//从bos的缓存中读出对象并返回
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
推荐使用第二种方法,因为如果存在多个需要深拷贝的对象,第一种方法需要逐个添加,而第二种反序列化的方法无需改动。