深入浅出设计模式笔记之四:原型模式

来源:互联网 发布:西门子802d编程实例 编辑:程序博客网 时间:2024/05/21 08:51

原型模式

 

引子

古人云:书非借不能读也。我深谙古人教诲,更何况现在 IT 书籍更新快、价格贵、质量水平更是参差不齐,实在不忍心看到用自己的血汗钱买的书不到半年就要被淘汰,更不想供养使用金山快译、词霸等现代化工具的翻译们。于是我去书店办了张借书卡,这样便没有了后顾之忧了——书不好我可以换嘛!但是,借书也有不爽的地方,就是看到有用或者比较重要的地方,不能在书旁标记下来。一般我会将这页内容复印下来,这样作为我自己的东西就可以对其圈圈画画,保存下来了。在软件设计中,往往也会遇到类似或者相似的问题,GOF     将这种解决方案叫作原型模式。也许原形模式会给你一些新的启迪。

 

定义与结构

原型模式属于对象创建模式,GOF  给它的定义为:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。在 Java 中提供了 clone()方法来实现对象的克隆,所以 Prototype 模式实现变得简单许多。注:clone()方法的使用,请参考《Thinking in Java》或者《EffectiveJava》,对于许多原型模式中讲到的浅克隆、深克隆,本文不作为谈论话题。使用克隆方式来创建对象与同样用来创建对象的工厂模式有什么不同?前面已经提过工厂模式对新产品的适应能力比较弱:创建新的产品时,就必须修改或者增加工厂角色。而且为了创建产品对象要先额外的创建一个工厂对象。那通过原型模式来创建对象会是什么样子呢?

先让我们来看看原型模式的结构吧。
1)   客户角色:让一个原型克隆自己来得到一个新对象。
2)   抽象原型角色:实现了自己的 clone 方法,扮演这种角色的类通常是抽象类,且它具有许多具体的子类。
3)   具体原型角色:被复制的对象,为抽象原型角色的具体子类。放上一张类图:

按照定义客户角色不仅要负责使用对象,而且还要负责对象原型的生成和克隆。这样造成客户角色分工就不是很明确,所以我们把对象原型生成和克隆功能单拿出来放到一个原型管理器中。原型管理器维护了已有原型的清单。客户在使用时会向原型管理器发出请求,而且可以修改原型管理器维护的清单。这样客户不需要编码就可以实现系统的扩展。

类图表示如下:




这样当客户自定义新的产品对象时,同时向原型管理器注册一个原型对象,而使用的类只需要根据客户的需要来从原型管理器中得到一个对象就可以了。这样就使得功能扩展变得容易些。

原型模式与其它创建型模式有着相同的特点:它们都将具体产品的创建过程进行包装,使得客户对创建不可知。就像上面例子中一样,客户程序仅仅知道一个抽象产品的接口。当然它还有过人之处:通过增加或者删除原型管理器中注册的对象,可以比其它创建型模式更方便的在运行时增加或者删除产品。

如果一个对象的创建总是由几种固定组件不同方式组合而成;如果对象之间仅仅实例属性不同。将不同情况的对象缓存起来,直接克隆使用。也许这比采用传递参数重新 new 一个对象要来的快一些。

你也许已经发现原型模式与工厂模式有着千丝万缕的联系:原型管理器不就是一个工厂么。当然这个工厂经过了改进(例如上例采用了 java 的反射机制),去掉了像抽象工厂模式或者工厂方法模式那样繁多的子类。因此可以说原型模式就是在工厂模式的基础上加入了克隆方法。也许你要说:我实在看不出来使用 clone 方法产生对象和 new   一个对象有什么区别;


原型模式使用 clone 能够动态的抽取当前对象运行时的状态并且克隆到新的对象中,新对象就可以在此基础上进行操作而不损坏原有对象;而 new 只能得到一个刚初始化的对象,而在实际应用中,这往往是不够的。特别当你的系统需要良好的扩展性时,在设计中使用原型模式也是很必要的。比如说,你的系统可以让客户自定义自己需要的类别,但是这种类别的初始化可能需要传递多于已有类别的参数,而这使得用它的类将不知道怎么来初始化它(因为已经写死了),除非对类进行修改。可见 clone 方法是不能使用构造函数来代替的。

 

分析了这么多了,举一个使用原型模式较为经典的例子:绩效考核软件要对今年的各种考核数据进行年度分析,而这一组数据是存放在数据库中的。一般我们会将这一组数据封装在一个类中,然后将此类的一个实例作为参数传入分析算法中进行分析,得到的分析结果返回到类中相应的变量中。假设我们决定对这组数据还要做另外一种分析以对分析结果进行比较评定。这时对封装有这组数据的类进行 clone 要比再次连接数据库得到数据好的多。任何模式都是存在缺陷的。原型模式主要的缺陷就是每个原型必须含clone 方法,在已有类的基础上来添加 clone 操作是比较困难的;而且当内部包括一些不支持 copy 或者循环引用的对象时,实现就更加困难了。

 

总结

由于 clone 方法在 java 实现中有着一定的弊端和风险,所以 clone 方法是不建议使用的。因此很少能在 java 应用中看到原型模式的使用。但是原型模式还是能够给我们一些启迪。


原创粉丝点击