`
xyheqhd888
  • 浏览: 404116 次
  • 性别: Icon_minigender_1
  • 来自: 秦皇岛
社区版块
存档分类
最新评论

Prototype(原型)模式

阅读更多

Prototype模式不通过实例化类来创建一个新的未初始化的实例,而是通过复制一个现有的对象来生成新的对象。

  

1.作为工厂的原型

   假定Oozinoz公司的应用系统通过使用抽象工厂模式为不同的应用场合提供不同的图形用户界面。如下图列出了所用到的用户接口工厂:


三个抽象工厂(或称工具包)可以产生三种不同的“外观和感觉”的用户界面

 

   Oozinoz公司的应用程序可以为用户在不同的应用场合提供合适的界面。但是当用户提出他们需要更多的用户界面工具包时,该系统存在以下问题:如果分别为用户指定的每种场合都提供一个用户接口工厂类,将会为我们带来繁重的工作量。为了避免用户接口工厂类的不断增加,Oozinoz应用系统开发者建议使用ProtoType模式:

(1)停止使用UIKit子类;

(2)让UIKit类的每个实例成为一个用户接口工厂,可以分发原型控件的副本;

(3)把静态方法中创建UIKit对象的代码放入UIKit类中。

根据这种设计,UIKit对象将拥有完整的原型实例变量集合:一个按钮对象,一个网格对象,一个可滑动面板对象等。创建新UIKit对象的代码也会设置这些原型控件的属性,以便得到期望的界面效果。create-()方法返回这些原型控件的副本。

  例如,我们可以在UIKit类中提供静态的handledUI()方法。这个方法会实例化UIKit,设置适合手持设备的对象实例变量,以及返回用作GUI工具集的对象。

 

突破题:如果使用Prototype模式,Oozinoz应用系统用于维护多个GUI工具集的类的数量会减少。请列出这种设计方法的其他优缺点。

答:优点包括:

   (1)可以在不创建新类的前提下创建新工厂;甚至可以在运行时创建一个新的GUI。  

   (2)我们可以这样创建一个新的GUI工具集,与老工具集的差别只在于字体不同。借助于原型方法,新工厂的按钮和其他控件可以从以前的工厂“继承”值,诸如颜色。

     缺点包括:

   (1)Prototype模式方法允许我们修改每个工厂的属性值,诸如颜色和字体,但是不允许我们创建具有不同行为的新工具集。

   (2)终止UI工具集进一步扩充的原因不清楚;为什么进一步扩充存在问题?我们必须把工具集初始化代码放在建议的UIKit类的静态方法中。这种方法并不能真正减少需要管理的代码的数量。

    到底那种答案正确?在类似的情况下,最好进行实验。编写遵循上述两种思路的代码,看看不同设计思路的真实效果如何。有时候,当项目组成员的分歧很大时,就应该采取试验的方式来辅助判断和决策。有时候,你确实拿定主意见了,会求助于架构师、首席设计师或者中立的第三者来做出判断。

 

     创建对象的常规方式是调用类的构造器。Prototype模式则可提供一个灵活的解决方案,让你可以在运行时决定使用哪个对象作为新对象的模板。然而,Java中的原形方法不允许对象拥有与父对象不同的方法。这时候,在使用原型方法之前,需要仔细考虑原型方法的利弊,甚至要试试此模式是否满足需求。为了使用Prototype模式,需要掌握Java语言复制对象的机制。

 

2.利用克隆进行原型化:   

   Prototype模式的主要目的是通过复制样本来创建新对象。复制对象时,新对象具备与父对象相同的属性和方法。新对象也许还会从父对象继承部分或者全部的数据值。比如,滑动面板的副本应该具有与原面板相同的滑动属性数据值。

   现在需要关注一个重要问题:复制对象时,复制操作会提供原始对象属性值的副本吗?还是副本与原始对象共享这些属性值?必须理解复制的工作机制,尤其是当你想使用Prototype模式时。

 

突破题:关于clone()方法的使用:

答:clone()方法的功能:新对象,相同的字段。clone()方法创建一个新对象,这个新对象与原对象的类型相同,新对象的属性与原对象的属性也完全相同。如果这些字段的类型是基础类型,如整型,则字段值也会被复制。如果字段是引用,则引用不会被复制。

clone()方法创建的对象是浅复制,与原对象共享任何下级对象。深复制是对所有父对象属性的完全复制。比如,如果克隆一个指向对象B的对象A,浅复制只会创建一个新的A对象,新的A对象指向原来的B对象;深复制会创建新的A对象,新的A指向新的B。如果希望使用深复制,你必须自己实现自己期望的内容复制。

   为了使用clone()方法,必须把自己的类声明为implements Cloneable.Cloneable是个标记接口,没有方法,只是充当一个标记来说明你有意支持clone()。

 

    借助于clone()方法,我们很容易往类中添加copy()方法。比如,你可以使用如下代码创建可克隆面板的类:

package com.oozinoz.ui;
import javax.swing.JPanel;

public class OzPanel extends JPanel implements Cloneable
{
     //dangerous!
     public  OzPanel copy()
     {
          return (OzPanel) this.close();
     }
     //...
} 

上述代码中的copy()方法使得大家都可以使用克隆功能,并且复制对象为所需的类型。这部分代码存的问题是,clone()方法会创建某JPanel对象所有属性的副本,不管你是否理解这些属性的功能。OzPanel类的属性包括它的超类的所有属性。大约70多个。

 

    OzPanel类从Component类继承了大量属性,而这些属性通常是操作GUI对象时需要复制的属性。

    

突破题:完善copy2()方法,使其能够不使用clone()方法就能实现面板复制。假设对面板来说最重要的属性是backgroud,font和foreground。

答:

public OzPanel copy2()
{
   OzPanel result  = new OzPanel();
   result.setBackGround(this.getBackground());
   result.setForeground(this.getForeground());
   result.setFont(this.getFont());
   return result;
}

  copy()方法和copy2()方法使得OzPanel的客户端无需调用构造器,并支持Prototype模式思想。然而,copy2()的人工方法也许更加安全。这个方法知道哪些属性最需要复制,但是避免复制自己不了解的属性。

 

 

3.小结

   借助Prototype模式,用户可以通过复制对象样本来创建新的对象。调用构造器创建新对象和复制对象来创建新对象,这两者最大的区别在于,通过复制创建的新对象一般会含有原始对象的某些状态。我们可以充分利用这个特点,尤其是当几个对象的类在属性上仅存在一点差别,而在行为上完全相同的时候。在这种情况下,我们可以通过为用户提供一个可以复制的对象原型,在运行时动态创建新类。

   当我们需要复制对象的时候,可以借助Object.clone()方法。但是必须记住,利用该方法创建的新对象与对象原型属性字段是完全相同的。通过这种复制方法获得的新对象可能并不是开发者所期望的副本,而且任何进一步的复制工作都需要由开发者来完成。如果进一步的复制工作过于错综复杂或者对象原型的字段太多,那么我们可以先实例化一个新对象,然后将对象原型中我们需要的字段赋给新对象的对应字段。

  • 大小: 2.8 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics