原型(Prototype)模式属于对象创建模式,是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
先让我们来看看原型模式的结构吧。
1) 客户角色:让一个原型克隆自己来得到一个新对象。
2) 抽象原型角色:实现了自己的clone 方法,扮演这种角色的类通常是抽象类,且它具有许多具体的子类。
3) 具体原型角色:被复制的对象,为抽象原型角色的具体子类。
按照定义客户角色不仅要负责使用对象,而且还要负责对象原型的生成和克隆。这样造成客户角色分工就不是很明确,所以我们把对象原型生成和克隆功能单拿出来放到一个原型管理器中。原型管理器维护了已有原型的清单。客户在使用时会向原型管理器发出请求,而且可以修改原型管理器维护的清单。这样客户不需要编码就可以实现系统的扩展。
class PrototypeManager { private static PrototypeManager pm; private Map prototypes=null; private PrototypeManager() { prototypes=new HashMap(); } //使用单例模式来得到原型管理器的唯一实例 public static PrototypeManager getManager() { if(pm==null) { pm=new PrototypeManager(); } return pm; } public void register(String name , Object prototype) { prototypes.put(name , prototype); } public void unregister(String name) { prototypes.remove(name); } public Prototype getPrototype(String name) { if(prototypes.containsKey(name)) { //将清单中对应原型的复制品返回给客户 return (Prototype) ((Prototype)prototypes.get(name)).clone(); }else { Prototype object=null; try { object =(Prototype)Class.forName(name).newInstance(); register(name , object); } catch(Exception e) { System.err.println("Class "+name+"没有定义!"); } return object; 。。。}
//先new 一个具体原型角色作为样本
Prototype p = new ConcretePrototype();
……
//使用原型p 克隆出一个新对象p1
Prototype p1 = (Prototype)p.clone();
看完上面的代码,有点糊涂,这个不是和工厂模式很类似麽,只是工厂模式是new一个对象出来,这里是利用反射机制注册一个对象。
原型管理器不就是一个工厂么。当然这个工厂经过了改进(例如上例采用了java 的反射机制),去掉了像抽象工厂模式或者工厂方法模式那样繁多的子类。因此可以说原型模式就是在工厂模式的基础上加入了克隆方法。也许你要说:我实在看不出来使用 clone 方法产生对象和new 一个对象有什么区别;原型模式使用clone 能够动态的抽取当前对象运行时的状态并且克隆到新的对象中,新对象就可以在此基础上进行操作而不损坏原有对象;而new 只能得到一个刚初始化的对象,而在实际应用中,这往往是不的。特别当你的系统需要良好的扩展性时,在设计中使用原型模式也是很必要的。比如说,你的系统可以让客户自定义自己需要的类别,但是这种类别的初始化可能需要传递多于已有类别的参数,而这使得用它的类将不知道怎么来初始化它(因为已经写死了),除非对类进行修改。可见 clone 方法是不能使用构造函数来代替的。
任何模式都是存在缺陷的。原型模式主要的缺陷就是每个原型必须含有clone 方法,在已有类的基础上来添加clone 操作是比较困难的;而且当内部包括一些不支持copy 或者循环引用的对象时,实现就更加困难了。