原型模式(Prototype Pattern)是 创建型模式 的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。
适用场景
- 类初始化消耗资源较多
- new产生的对象需要比较繁琐的过程
- 构造函数比较复杂
- 循环体内产生大量的对象
简单克隆
创建基础ConcretePrototype,它实现了Prototype
的clone()
。
public class ConcretePrototype implements Prototype {
private int age;
private List hobbis;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List getHobbis() {
return hobbis;
}
public void setHobbis(List hobbis) {
this.hobbis = hobbis;
}
@Override
public Prototype clone() {
ConcretePrototype concretePrototype = new ConcretePrototype();
concretePrototype.setAge(this.age);
concretePrototype.setHobbis(this.hobbis);
return concretePrototype;
}
}
创建测试类,查看复制结果。
public class Test {
public static void main(String[] args) {
ConcretePrototype concretePrototype = new ConcretePrototype();
concretePrototype.setAge(15);
List<String> list = new ArrayList<>();
concretePrototype.setHobbis(list);
ConcretePrototype concretePrototype1 = (ConcretePrototype) concretePrototype.clone();
System.out.println("克隆对象引用地址"+(concretePrototype == concretePrototype1));
System.out.println("克隆属性引用地址"+(concretePrototype.getHobbis() == concretePrototype1.getHobbis()));
}
}
可以看出,我们确实复制了一个新的类。但是hobbies的应用地址却是相同的,意味着我们复制的并不是值,而是引用的地址。这就是我们常说的浅克隆。
浅克隆
复制出来的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。
深克隆
复制出来的所有变量都含有与原来的对象相同的值,那些引用其他对象的变量将指向复制出来的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
深克隆实现版
我们使用孙悟空的作为模型。猴哥猴哥,你真了不得,拔一根毫毛吹出猴万个,但是每只猴子都有个金箍棒,而这个金箍棒的复制应该就属于深克隆。接下来我们实现一下。
首先创建一个可序列化的金箍棒
public class Jingubang implements Serializable {
public float h = 100;
public float d = 10;
}
再创建一个悟空
public class Wukong implements Cloneable, Serializable {
private int height;
private int weight;
private Jingubang jingubang;
public Wukong() {
this.height = 1;
this.weight = 1;
this.jingubang = new Jingubang();
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public Jingubang getJingubang() {
return jingubang;
}
public void setJingubang(Jingubang jingubang) {
this.jingubang = jingubang;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return deepClone();
}
public Wukong deepClone(){
try {
ByteOutputStream byteOutputStream = new ByteOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
objectOutputStream.writeObject(this);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
Wukong copy = (Wukong) objectInputStream.readObject();
return copy;
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}
使用序列化复制生成实例。
public class WukongTest {
public static void main(String[] args) {
Wukong sunweukong = new Wukong();
Wukong liuermihou = null;
try {
liuermihou = (Wukong) sunweukong.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
System.out.println(sunweukong.getJingubang());
System.out.println(liuermihou.getJingubang());
System.out.println("克隆对象引用地址"+(sunweukong == liuermihou));
System.out.println("克隆属性引用地址"+(sunweukong.getJingubang() == liuermihou.getJingubang()));
}
}
由测试可以看出,我们复制生成的实例,已经完全是全新的实例了。