对于原型模式的理解
通过实现Cloneable接口,并重写父类(即Object)的clone方法来返回和该对象一模一样的对象来实现实例化一个新对象的效果。
比较官方的解释是:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。
实现代码
public class Prototype implements Cloneable{
private String address;
private String phoneNum;
private String name;
private Product product;
public Prototype(String address, String phoneNum, String name, Product product) {
this.address = address;
this.phoneNum = phoneNum;
this.name = name;
this.product = product;
}
// 省略get/set方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Product {
private String name;
private String price;
public Product(String name, String price) {
this.name = name;
this.price = price;
}
}
先实例化一个对象,然后通过其clone方法复制出一个新的对象
public static void main(String[] args) {
Product product = new Product("d","e");
System.out.println(product);
Prototype prototype = new Prototype("a","b","c",product);
System.out.println(prototype);
try {
Prototype clone =(Prototype) prototype.clone();
System.out.println(clone);
System.out.println(clone.getProduct());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
可以看到两个prototype对象的地址是不一样的,但是product对象的地址是一样的。
com.Test.Product@7adf9f5f
com.Test.Prototype@85ede7b
com.Test.Prototype@5674cd4d
com.Test.Product@7adf9f5f
浅复制与深复制
可以看到复制的prototype对象是一个新的地址,但是其成员变量product的地址是一样,他们都引用了同一个对象,这种复制是浅复制。当其中一个对象修改product对象的成员变量时,另一个prototype对象的product也会跟着改变。我们希望在进行复制的时候也将product复制一份而不是指向同一个引用,这样的复制是深复制。
public class Product implements Cloneable{
private String name;
private String price;
public Product(String name, String price) {
this.name = name;
this.price = price;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Prototype implements Cloneable{
private String address;
private String phoneNum;
private String name;
private Product product;
public Prototype(String address, String phoneNum, String name, Product product) {
this.address = address;
this.phoneNum = phoneNum;
this.name = name;
this.product = product;
}
// 省略get/set方法
@Override
protected Prototype clone() throws CloneNotSupportedException {
final Prototype clone =(Prototype) super.clone();
clone.setProduct((Product) clone.getProduct().clone());
return clone;
}
}
com.Test.Product@7adf9f5f
com.Test.Prototype@85ede7b
com.Test.Prototype@5674cd4d
com.Test.Product@63961c42
可以看到两个product对象的地址是不一样的了。
原型模式实现的关键就是要实现clone方法,Object类是所有类默认的父类,其自带clone方法,而且这个方法是protect性质的,也就是说每一个类都能重写clone方法,但是要想这个类具备复制的能力就一定实现cloneable接口,不然就是抛出CloneNotSupportedException异常。
还有一点就是 String类型的变量不会存在深浅复制这样的问题。
原型模式的作用
第一点好处就是:不用重复的初始化对象,而是动态地获得对象运行时的状态。
第二点好处就是:在初始化信息不好生变化或者变化不是很大的情况下,这种方式隐藏了对象创建的细节,又对性能是大大提升(clone方式是一个native方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。)