模式定义
Prototype原型模式将创建一个对象定义为一个原型实例,并且通过拷贝这些原型来创建新的相似的对象。
使用范围
- 当需要创建的一组对象在组织结构与内部实现上有很强的相似性时
- 原型与克隆后的对象互不相干
使用方法
对于原型Prototype我们可以将它定义为抽象类,实现了Cloneable接口的方法Clone()。所有的它的子类将会拥有父类的Clone方法并返回自己的一个对象拷贝。这里涉及到一个Shallow Clone和Deep Clone的区别,Shallow Clone是对原型对象的一个引用,不管改变原型还是克隆后的对象的值,都会影响对方相应的值;Deep Clone会克隆所有Prototype内包含的所有对象(非基本数据类型),克隆后的副本与原型不共享相同的内存地址,人为地修改其中一方不会影响另一方。
举例说明
假设需要建设一个房子,房子需要有房间和花园。这里定义House对象而非用基本数据类型是为了说明Deep Clone的方法,因此House实现了Cloneable的Clone方法。如果要演示Shallow Clone,则无须实现Cloneable接口。
public class House implements Cloneable {
String room;
String garden;
public String getRoom() {
return room;
}
public void setRoom(String room) {
this.room = room;
}
public String getGarden() {
return garden;
}
public void setGarden(String garden) {
this.garden = garden;
}
public Object clone() {
House object = null;
try {
object = (House) super.clone();
} catch (CloneNotSupportedException exception) {
System.err.println("House not Cloneable");
}
return object;
}
}
AbstractArchitect顾名思义就是一个抽象类的建筑师,他是一个原型,实现Cloneable接口的Clone方法,为了实现对象的Shallow Clone。
public abstract class AbstractArchitect implements Cloneable {
House house = new House();
public abstract void buildRoom(String room);
public abstract void buildGarden(String garden);
public Object clone() {
AbstractArchitect object = null;
try {
object = (AbstractArchitect) super.clone();
} catch (CloneNotSupportedException exception) {
System.err.println("AbstractArchitect not Cloneable");
}
return object;
}
}
Architect是实例化的子类。
public class Architect extends AbstractArchitect {
public void buildRoom(String room) {
house.setRoom(room);
}
public void buildGarden(String garden) {
house.setGarden(garden);
}
}
客户端代码演示了如何实现Shallow Clone。
public class Client {
public static void main(String args[]) {
System.out.println("Shallow Clone");
AbstractArchitect a1 = new Architect();
a1.buildRoom("4 rooms");
a1.buildGarden("beautiful garden");
AbstractArchitect a2 = (AbstractArchitect) a1.clone();
System.out.println("A1:" + a1.house.getRoom() + "," + a1.house.getGarden());
System.out.println("A2:" + a2.house.getRoom() + "," + a2.house.getGarden());
a1.buildRoom("50 rooms");
a1.buildGarden("ugly garden");
System.out.println("A1:" + a1.house.getRoom() + "," + a1.house.getGarden());
System.out.println("A2:" + a2.house.getRoom() + "," + a2.house.getGarden());
}
}
运行结果为:
Shallow Clone
A1:4 rooms,beautiful garden
A2:4 rooms,beautiful garden
A1:50 rooms,ugly garden
A2:50 rooms,ugly garden
我们可以看到a2克隆了a1,其后a1改变了其内部对象的属性值,a2也跟着改变了,原因在于a2克隆了a1,但是没有克隆a1内部的一个复杂对象即House,因为在AbstractArchitect的Clone()内没有对House进行Clone(),因此 a2和a1都包含了对同一个House对象的引用。
一般情况地下,通常的编程都会要求能克隆原型的一个初始的副本,其后各自对象内部的值互不影响,为实现这种理想状况,需要采用Deep Clone方法,克隆原型内的所有复杂对象。
定义一个深度克隆的原型DeepCloneAbstractArchitect,在方法Clone()中实现了内部对象的再Clone,即object.house.clone();
public abstract class DeepCloneAbstractArchitect implements Cloneable {
House house = new House();
public abstract void buildRoom(String room);
public abstract void buildGarden(String garden);
public Object clone() {
DeepCloneAbstractArchitect object = null;
try {
object = (DeepCloneAbstractArchitect) super.clone();
house = (House) object.house.clone();
} catch (CloneNotSupportedException exception) {
System.err.println("DeepCloneAbstractArchitect not Cloneable");
}
return object;
}
}
子类DeepCloneArchitect
public class DeepCloneArchitect extends DeepCloneAbstractArchitect {
public void buildRoom(String room) {
house.setRoom(room);
}
public void buildGarden(String garden) {
house.setGarden(garden);
}
}
客户端实现原型的深度克隆
public class Client {
public static void main(String args[]) {
System.out.println("/nDeep Clone");
DeepCloneAbstractArchitect b1 = new DeepCloneArchitect();
b1.buildRoom("4 rooms");
b1.buildGarden("beautiful garden");
DeepCloneAbstractArchitect b2 = (DeepCloneAbstractArchitect) b1.clone();
System.out.println("B1:" + b1.house.getRoom() + "," + b1.house.getGarden());
System.out.println("B2:" + b2.house.getRoom() + "," + b2.house.getGarden());
b1.buildRoom("50 rooms");
b1.buildGarden("ugly garden");
System.out.println("B1:" + b1.house.getRoom() + "," + b1.house.getGarden());
System.out.println("B2:" + b2.house.getRoom() + "," + b2.house.getGarden());
}
}
结果为:
Deep Clone
B1:4 rooms,beautiful garden
B2:4 rooms,beautiful garden
B1:50 rooms,ugly garden
B2:4 rooms,beautiful garden
可见b2保存了b1的一个初始副本,以后两个对象互不相关,真正实现了Prototype的初衷。
类图如下:
下载示例