深入浅出原型模式

原创 2005年01月02日 15:54:00

一、引子<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

古人云:书非借不能读也。我深谙古人教诲,更何况现在IT书籍更新快、价格贵、质量水平更是参差不齐,实在不忍心看到用自己的血汗钱买的书不到半年就要被淘汰,更不想供养使用金山快译、词霸等现代化工具的翻译们。于是我去书店办了张借书卡,这样便没有了后顾之忧了——书不好我可以换嘛!

但是,借书也有不爽的地方,就是看到有用或者比较重要的地方,不能在书旁标记下来。一般我会将这页内容复印下来,这样作为我自己的东西就可以对其圈圈画画,保存下来了。

在软件设计中,往往也会遇到类似或者相似的问题,GOF将这种解决方案叫作原型模式。也许原形模式会给你一些新的启迪。

 

二、定义与结构

原型模式属于对象创建模式,GOF给它的定义为:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

Java中提供了clone()方法来实现对象的克隆,所以Prototype模式实现变得简单许多。注:clone()方法的使用,请参考《Thinking in Java》或者《Effective Java》,对于许多原型模式中讲到的浅克隆、深克隆,本文不作为谈论话题。

       但是在什么情况下使用原型模式最为合适呢?它能给我们带来什么好处呢?这些问题不是看上一两行教学代码能够解决的。在这里我会尽力着重来讨论这两个问题。

       我认为原型模式应该是为了弥补工厂方法模式的弱点而产生,在前面已经讲过——工厂方法模式对于适应产品变化方面比较弱,添加删除一种产品都会额外引起工厂类的相应变化。那么在原型模式中,是如何来适应这种变化的呢?往下看……

       先让我们来看看原型模式的结构吧。

1)         客户角色:让一个原型克隆自己来得到一个新对象。

2)       抽象原型角色:实现了自己的clone方法,扮演这种角色的类通常是抽象类,且它具有许多具体的子类。

3)       具体原型角色:被复制的对象,为抽象原型角色的具体子类。          

放上一张类图来形象地表示出来:

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

 

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

       类图表示如下:

 

 

 

三、分析

对于抽象原型角色和具体原型角色,它们就是一个继承或者实现关系,没有什么好讲的,记住实现好clone方法就好了。

那么客户是怎么来使用这些角色的对像的呢?来看两行简要的代码

//new一个具体原型角色

Prototype p = new ConcretePrototype();

……

//使用原型p克隆出一个新对象p1

       Prototype p1 = (Prototype)p.clone();

 

也许你要说:我实在看不出来使用clone方法产生对象和new 一个对象有什么区别。让我们先来看下原型模式能给我们带来什么。原型模式使用clone能够动态的抽取当前对象运行时的状态并且克隆到新的对象中,新对象就可以在此基础上进行操作而不损坏原有对象;而new只能得到一个刚初始化的对象,而在实际应用中,这往往是不够的。

       特别当你的系统需要良好的扩展性时,在设计中使用原型模式也是很必要的。比如说,你的系统可以让客户自定义自己需要的类别,但是这种类别的初始化可能需要传递多于已有类别的参数,而这使得用它的类将不知道怎么来初始化它(因为已经写死了),除非对类进行修改。而这在客户那里显然是行不通的。

       如果在设计时考虑以上弊端而采用了原型模式,当客户自定义自己的类别的时候,同时向原型管理器注册一个原型对象,而使用的类只需要根据客户的需要来从原型管理器中得到一个对象就可以了。这样就使得功能扩展变得容易些。

       可见clone方法是不能使用构造函数来代替的。

原型模式还体现了OO中的多态性——当别人需要我的副本时,我只管克隆我自己,但是我的具体类型我并不关心,这一切要到运行时才能知道。

至于上面提到的原型管理器的实现,简单来说就是对原型清单的维护。可以考虑一下几点:要保存一个原型对象的清单,我们可以使用一个HashMap来实现,使原型对象和它的名字相对应;原型管理器只需要一个就够了,所以可以使用单例模式来实现控制;实现得到、注册、删除原型对象的功能只是对HashMap的对应操作而已。代码如下:

class PrototypeManager {
       private static PrototypeManager pm;
       private Map prototypes=null;
       private PrototypeManager() {
              prototypes=new HashMap();
       }

//使用单例模式来得到原型管理器的唯一实例
       public static synchronized 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 =
PrototypeClass.forName(name).newInstance();
                            register(name , object);
                     }  catch(Exception e) {
                            System.err.println("Class "+name+"
没有定义
!");
                     }
                     return object;

 
。。。

 

分析了这么多了,举一个使用原型模式较为经典的例子:绩效考核软件要对今年的各种考核数据进行年度分析,而这一组数据是存放在数据库中的。一般我们会将这一组数据封装在一个类中,然后将此类的一个实例作为参数传入分析算法中进行分析,分析结果放入对象的相应变量中。假设我们决定对这组数据还要做另外一种分析以对分析结果进行比较评定。这时对封装有这组数据的类进行clone要比再次连接数据库得到数据好的多。

上面我分析了使用原型模式的一些好处,下面来看下它的缺陷吧。原型模式主要的缺陷就是每个原型必须含有clone方法,在已有类的基础上来添加clone操作是比较困难的;而且当内部包括一些不支持copy或者循环引用的对象时,实现就更加困难了。而且使用clone方法要对深克隆、浅克隆深入了解,不然很可能掉进陷阱,给系统埋下遗患。

 

四、总结

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

设计模式(六)原型模式

一、说说鸣人的影分身 话说鸣人听了水木老师的建议偷出了卷轴并且学会了一招禁术:影分身之术。当鸣人使用影分身之术的时候就会有好多个和鸣人一模一样的人出现,就像复制出来的一样,这种影分身之术在面向对象的...
  • xingjiarong
  • xingjiarong
  • 2015年11月28日 16:13
  • 1680

原型模式的使用分析

原型模式是一种简单、易使用的创建型设计模式,通过给出一个原型对象来指明所创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以...
  • u010024991
  • u010024991
  • 2016年12月02日 11:18
  • 1260

Java设计模式——原型模式

原型模式是为了解决一些不必要的对象创建过程。当Java JDK中提供了Cloneable接口之后,原型模式就变得异常的简单了。虽然由于Cloneable的引入使用程序变得更简单了,不过还是有一些需要说...
  • u013761665
  • u013761665
  • 2016年03月03日 13:50
  • 1969

设计模式--原型模式

1.设计模式分类         所谓设计模式,是前人在开发过程中总结的经验。各自有各自的使用情况。分类条件不同 设计模式的分类也不尽相同。编程之道中大致分类如下 创建型 包括 单例设计模式,简单工厂...
  • a316212802
  • a316212802
  • 2015年11月13日 18:45
  • 998

JavaScript 原型模式

JavaScript原型模式 1. 普通对象 var o1 = {} var o2 = new Object() var o3 = new f1() 除了函数对象就是普通对象 2. ...
  • qq_38860226
  • qq_38860226
  • 2018年01月16日 10:03
  • 22

C++原型模式

原型模式(Prototype Pattern)是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,而无需知道任何创建的细节。...
  • u011012932
  • u011012932
  • 2017年03月27日 11:39
  • 1176

iOS 设计模式之原型模式 (Prototype)

原型模式从一个对象在创建另一个对象,而不需知道任何创建细节。一般在初始化信息不变化的情况下,使用原型模式是最好的方法,即隐藏了对象创建的细节,对性能又大大提高。在 iOS 开发中,体现原型模式的是 c...
  • a12a33
  • a12a33
  • 2016年02月23日 09:36
  • 440

Java设计模式(五) 原型模式详解

在开发过程中,有时会遇到为一个类创建多个实例的情况,这些实例内部成员往往完全相同或有细微的差异,而且实例的创建开销比较大或者需要输入较多参数,如果能通过复制一个已创建的对象实例来重复创建多个相同的对象...
  • u013916933
  • u013916933
  • 2016年06月04日 16:22
  • 3023

JAVA设计模式之原型模式

定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。 类型:创建类模式 类图: 原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype...
  • jason0539
  • jason0539
  • 2014年04月08日 08:22
  • 15360

【C#设计模式-原型模式】

创建型模式中一个比较特殊的模式-原型模式,这个模式呢,有个最大的特点是克隆一个现有的对象,这个克隆的结果有2种,一种是浅度复制,另一种是深度复制。 创建型模式一般是用来创建一个新的对象,然后我们使用这...
  • heyangyi_19940703
  • heyangyi_19940703
  • 2016年04月25日 13:18
  • 1459
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深入浅出原型模式
举报原因:
原因补充:

(最多只允许输入30个字)