原型模式
● 以某个对象为原型,复制出新的对象,显然,新的对象具有原型对象的所有特点
● 当通过new创建一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
● 优势:效率高,避免了重新执行构造过程步骤
● new创建出的对象属性值采用的是默认值,而克隆出的对象属性值与原型对象完全相同并且不会影响原型对象
原型模式的实现
- 原型类要实现Cloneable接口
- 实现clone()方法
浅克隆
原型类(Sheep.java)
public class Sheep implements Cloneable{
private String name;
private Date birthday;
//重写Object类的clone()方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
return obj;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Sheep(String name, Date birthday) {
super();
this.name = name;
this.birthday = birthday;
}
public Sheep() {
super();
// TODO Auto-generated constructor stub
}
}
测试
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date(123123123123L);
Sheep s1 = new Sheep("少莉",date); //实例化原型对象
System.out.println(s1);
System.out.println(s1.getName());
System.out.println(s1.getBirthday());
Sheep s2 = (Sheep) s1.clone(); //调用clone()方法克隆出新对象
System.out.println(s2);
System.out.println(s2.getName());
System.out.println(s2.getBirthday());
}
}
由运行结果我们可以发现,虽然两个对象不是同一个对象,但他们的属性值是完全一样的
然后,我们修改新对象name属性值
可以看到只有新对象的值改变了,而原型对象没有改变
接下来,解释为什么这种方式称为浅克隆
在浅克隆中,原型对象中的成员变量是值类型,就复制一份给新对象;如果成员变量是引用类型,则将引用对象的地址复制给新对象。这样就会导致我们修改原型对象中引用类型变量的值,会导致克隆对象的值随之改变。
如何来解决这个问题呢,那就用深克隆来解决
深克隆有两种实现方式,一种是在clone()方法里添加代码,另一种是通过序列化与反序列化实现
添加代码的方式
原型类(sheep2.java)
public class Sheep2 implements Cloneable{
private String name;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
//深克隆
Sheep2 s = (Sheep2) obj;
s.birthday = (Date) this.birthday.clone(); //把属性进行克隆
return obj;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Sheep2(String name, Date birthday) {
super();
this.name = name;
this.birthday = birthday;
}
public Sheep2() {
super();
// TODO Auto-generated constructor stub
}
}
测试,可以看到只有原型对象的值改变了,进行深克隆之后,相当于创建了一个新的引用对象,里面的值是一样的,并把克隆对象的成员变量指向它。