所谓原型模式,就是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式不是利用类产生对象实例,而是从一个对象实例产生出另一个对象实例,复制建立对象。
命名由来是因为这个
Pattern
是根据被视为原型的对象实例,才能建立另一个新对象实例。
原型模式就是通过Java类的克隆方法实现的,这就要求每一个类都必须实现一个克隆方法,这对于全新的类来说并不是很难,而对于已经有的类就不大容易,应该在实现克隆方法时需要对类的功能进行通盘考虑,后面会提到浅克隆和深克隆的区别。特别是当一个类引用到不支持串行化serialize的节间对象,或者引用含有循环结构的时候。
实例如下(ProtoTypeSample.java JDK1.5测试通过):
import java.util.HashMap;
/**
*原型接口
*/
interface Action extends Cloneable{
public int execute();
public Object createClone();
}
/**
*具体原型类1
*/
class SubAction implements Action{
private int firstParam;
private int secondParam;
public SubAction(int param1,int param2){
System.out.println("create a subAction example");
this.firstParam = param1;
this.secondParam = param2;
}
public int execute(){
return firstParam - secondParam;
}
public Object createClone(){
Object o = null;
try{
o = super.clone();
}catch(Exception e){
}
return o;
}
}
/**
*具体原型类2
*/
class AddAction implements Action{
private int firstParam;
private int secondParam;
public AddAction(int param1,int param2){
System.out.println("Create a AddAction example");
this.firstParam = param1;
this.secondParam = param2;
}
public int execute(){
return firstParam + secondParam;
}
public Object createClone(){
Object o = null ;
try{
o = super.clone();
}catch(Exception e){
}
return o;
}
}
/**
*原型管理
*/
class ProtoTypeManager
{
private static HashMap ptMap = new HashMap();
public static void register(String name,Action action){
ptMap.put(name,action);
}
public static Action unRegister(String name){
return (Action)ptMap.remove(name);
}
public static Action createAction(String name){
//
return (Action)((Action)ptMap.get(name)).clone();
return (Action)((Action)ptMap.get(name)).createClone();
}
}
public class ProtoTypeSample{
public static void main(String[] args){
//被视为原型的实例
Action sub = new SubAction(4,55);
Action add = new AddAction(444,222);
ProtoTypeManager.register("sub",sub);
ProtoTypeManager.register("add",add);
Action tmp = (Action)ProtoTypeManager.unRegister("sub");
System.out.println(tmp.execute());
Action ptCreator = ProtoTypeManager.createAction("add");
System.out.println(ptCreator.execute());
}
}
使用原型模式而不是使用new关键字的区别在于,当一个对象处在一个复杂状态时,如果希望得到一个拷贝,同时又具有这个对象一模一样的状态,如果使用new,将不得不重新一个一个地来设置这些状态,有时候比较麻烦,有时候很难做到,此时如果使用原型模式,就将会是一个很好的解决方法。
在Object中,clone方法所做的操作就是直接复制字段内容,并不管该字段对应的对象实例内容,如果是一个通过new方式生成的对象,当你使用这种clone方法进行复制时,复制的结果只对应该对象的引用而已。在重写clone方法时,一定要注意避免“浅拷贝”,务必要做到“深拷贝”。Clone只会进行复制,不会调用构造函数。
在一个类中如果只包含基本数据类型,object提供的clone方法就足够,如果是由其他对象合并而成的,为了对其进行深层复制,super.clone()的结果必须造成成当前的对象,并对其中的对象进行深度克隆。如下例
class DeepObject implements Cloneable
{
CompiseObject obj1 = new CompiseObject();
CompiseObject ojb2 = new CompiseObject();
public Object clone(){
DeepObject o = null;
try{
o = (DeepObject)super.clone();
}catch(Exception e){
}
o.obj1 = (CompiseObject)o.obj1.clone();
o.obj2 = (CompiseObject)o.obj2.clone();
return 0;
}
}
如果对象中有Vector这样的成员,在克隆了Vector之后,必须在其中遍历,并克隆由Vector指向的每个对象,对于HashMap、Hashtable……也都必须采取类似的处理。
以前在对一个对象进行序列化以后再撤销对它的序列化,实际也就是一个克隆的过程。但序列化要比克隆要耗费多得多的时间,同时序列化技术的运行结果并不稳定,而克隆每一次花费的时间都是相同的。
在添加克隆能力之前,编译器会阻止我们的克隆尝试,一旦在层次结构中添加了克隆能力,那么当前添加的类以及它所有的子类都可以进行克隆.
Ref:
1、 Thinking In Java
2、 Java设计模式