Design Pattern: Prototype 模式

  学习是分享和合作式的!

转载请注明出处:http://blog.csdn.net/wdzxl198/article/details/9271773

文章摘自: http://www.riabook.cn/doc/designpattern/

您从图书馆的期刊从发现了几篇您感兴趣的文章,由于这是图书馆的书,您不可以直接在书中作记号或写字,所以您将当中您所感兴趣的几个主题影印出来,这下子您就可在影印的文章上画记重点。
Prototype模式的作用有些类似上面的描述,您在父类别中定义一个clone()方法,而在子类别中重新定义它,当客户端对于所产生的物件有兴趣并想加以利用,而您又不想破坏原来的物件,您可以产生一个物件的复本给它。
Prototype具有展示的意味,就像是展览会上的原型车款,当您对某个车款感兴趣时,您可以购买相同款示的车,而不是车展上的车。
在软体设计上的例子会更清楚的说明为何要进行物件复制,假设您要设计一个室内设计软体,软体中有一个展示家具的工具列,您只要点选工具列就可以产生一个家 具复本,例如一张椅子或桌子,您可以拖曳这个复制的物件至设计图中,随时改变它的位置、颜色等等,当您改变设计图中的物件时,工具列上的原型工具列是不会 跟着一起改变的,这个道理是无需解释的。
下面的 UML 类别图表示了上述的简单概念:

Prototype模式的重点在于clone(),它负责复制物件本身并传回,但这个clone()本身在实作上存在一些困难,尤其是当物件本身又继承另一个物件时,如何确保复制的物件完整无误,在不同的程式语言中有不同的作法。
在Java中的作法是透过实作一个Cloneable介面,它只是一个声明的介面,并无规定任何实作的方法,您的目的是改写Object的clone ()方法,使其具备有复制物件的功能,这个方面建议您参考:How to avoid traps and correctly override methods from java.lang.Object
用一个简单的例子来实作上图中的结构,这个例子利用了Java语言本身的clone特性:

  • AbstractFurniture.java
   1: public abstract class AbstractFurniture 
   2:                              implements Cloneable {
   3:     public abstract void draw();
   4:     
   5:     // 在Design Pattern上,以下的clone是抽象未实作的
   6:     // 实际上在Java中class都继承自Object
   7:     // 所以在这边我们直接重新定义clone() 
   8:     // 这是为了符合Java现行的clone机制
   9:     protected Object clone() throws CloneNotSupportedException { 
  10:         return super.clone(); 
  11:     }
  12: }

CircleTable与SquareTable继承了AbstractFurniture,并实作clone方法,用于传回本身的复制品:

  • CircleTable.java
   1: import java.awt.*;
   2:  
   3: public class CircleTable extends AbstractFurniture {
   4:     protected Point center;    
   5:     
   6:     public void setCenter(Point center) {
   7:         this.center = center;
   8:     }
   9:     
  10:     protected Object clone () 
  11:                      throws CloneNotSupportedException { 
  12:         Object o = super.clone(); 
  13:         if(this.center != null) {
  14:             ((CircleTable) o).center = (Point) center.clone();
  15:         }
  16:         
  17:         return o; 
  18:     } 
  19:  
  20:     public void draw() { 
  21:         System.out.println("\t圆桌\t中心:(" + center.getX() 
  22:                             + ", " + center.getY()+ ")");
  23:     } 
  24: }
  • SquareTable.java
   1: import java.awt.*;
   2:  
   3: public class SquareTable extends AbstractFurniture {
   4:     protected Rectangle rectangle;    
   5:     
   6:     public void setRectangle(Rectangle rectangle) {
   7:         this.rectangle = rectangle;
   8:     }
   9:     
  10:     protected Object clone () 
  11:                       throws CloneNotSupportedException { 
  12:         Object o = super.clone(); 
  13:         if(this.rectangle != null) { 
  14:             ((SquareTable) o).rectangle = (Rectangle) rectangle.clone();
  15:         }
  16:         
  17:         return o; 
  18:     } 
  19:  
  20:     public void draw() { 
  21:         System.out.print("\t方桌\t位置:(" + rectangle.getX() 
  22:                             + ", " + rectangle.getY()+ ")");
  23:         System.out.println(" / 宽高:(" + 
  24:                          rectangle.getWidth() 
  25:                 + ", " + rectangle.getHeight()+ ")");
  26:     }
  27: }

House是个虚拟的房屋物件,从Prototype复制出来的物件加入至House中:

  • House.java
   1: import java.util.*;
   2:  
   3: public class House { 
   4:     private Vector vector;
   5:  
   6:     public House() { 
   7:         vector = new Vector(); 
   8:     }
   9:  
  10:     public void addFurniture(AbstractFurniture furniture) { 
  11:         vector.addElement(furniture); 
  12:         
  13:         System.out.println("现有家具....");
  14:         
  15:         Enumeration enumeration = vector.elements();
  16:         while(enumeration.hasMoreElements()) { 
  17:              AbstractFurniture f = 
  18:                  (AbstractFurniture) enumeration.nextElement(); 
  19:              f.draw(); 
  20:         } 
  21:         System.out.println(); 
  22:     } 
  23: }

再来是应用程式本身:

  • Application.java
   1: import java.awt.*;
   2:  
   3: public class Application {
   4:     private AbstractFurniture circleTablePrototype;
   5:     
   6:     public void setCircleTablePrototype(
   7:                    AbstractFurniture circleTablePrototype) {
   8:         this.circleTablePrototype = circleTablePrototype;
   9:     }
  10:     
  11:     public void runAppExample() throws Exception {
  12:         House house = new House(); 
  13:         CircleTable circleTable = null;
  14:  
  15:         // 从工具列选择一个家具加入房子中
  16:         circleTable =
  17:             (CircleTable) circleTablePrototype.clone();
  18:         circleTable.setCenter(new Point(10, 10));
  19:         house.addFurniture(circleTable); 
  20:         
  21:         // 从工具列选择一个家具加入房子中
  22:         circleTable = 
  23:             (CircleTable) circleTablePrototype.clone();
  24:         circleTable.setCenter(new Point(20, 30));
  25:         house.addFurniture(circleTable); 
  26:     }
  27:     
  28:     public static void main(String[] args) throws Exception {
  29:         Application application = new Application();
  30:         application.setCircleTablePrototype(
  31:                             new CircleTable());
  32:         application.runAppExample();
  33:     }
  34: }

Java中的clone()方法是继承自Object,AbstractFurniture的子类别则override这个clone()方法,以复制其本身并传回。
下图为Prototype模式的类别结构图:

在 Gof 的设计模式书中给出一个原型模式的应用:一个通用的图型编辑器 Framework。在这个 Framework中有一个工具列,您可以在上面选择音乐符号以加入乐谱中,并可以随时调整音乐符号的位置等等。
图型编辑器Framework是通用的,然而它并不知道这些音乐符号的型态,有人或许会想到继承图型编辑器Framework来为每个音乐符号设计一个框 架子类别,但由于音乐符号的种类很多,这会产生相当多的子类别,为了避免这种情况,可以透过Prototype模式来减少子类别的数目,可以设计出以下的 结构:

依照这个结构,图型编辑器的Framework可以独立于要套用的特定类别之外,虽然不知道被复制传回的对象型态是什么,但总可以按照 Graphics所定义的介面来操作这些物件。

Edit by Atlas

Time 2013/7/8 14:41

时间: 2025-01-02 17:02:58

Design Pattern: Prototype 模式的相关文章

Design Pattern: Builder 模式

  学习是分享和合作式的! 转载请注明出处:http://blog.csdn.net/wdzxl198/article/details/9248365:  文章摘自: http://www.riabook.cn/doc/designpattern/:  您想要建立一个迷宫产生程式,迷宫使用二维阵列来定义,0表示道路,1表示墙,2表示宝物,根据所定义的二维迷宫阵列,您想要程式自动产生各种不同材质的迷宫,例如砖墙迷宫,钻石迷宫等等. 您可以在程式中定义两个角色,一个是指导迷宫建立的Director角

Design Pattern: Proxy 模式

学习是分享和合作式的! 转载请注明出处:http://blog.csdn.net/wdzxl198/article/details/10472999: 文章摘自: http://www.riabook.cn/doc/designpattern/: 在 Gof 的书中对Proxy模式的目的给定为:为其它的物件提供一种代理,以控制对这个物件的访问.由这句话所延伸出来的意思是,根据您的目的不同,您的代理物件将负有不同的责任,因为产生多种不同的代理情况. 根据不同的代理目的,而有不同的代理情况,在Gof

Design Pattern: Adapter 模式 - Object Adapter

您的电脑是个旧电脑,新的滑鼠都在使用USB接口了,而您的电脑上并没有USB,而只有一个PS2接口,这时您可以使用一个USB转PS2的接头作为转换,这样您的电脑就可以使用新滑鼠了(当然您也可以使用USB扩充卡,意思是相同的).  类似的概念,有时候您想在原来的程式中加入一个外部元件,例如一个类别,但是这个类别与您目前所设计的程式在介面上并不一致,为了让这个外部类与原程式的介面一致,您必须使用一个类别作为中介来配接它们,这时您可以采用Adapter模式.  举个例子来说,在Java 1.0中有个En

Design Pattern: Singleton 模式

一句话概括:保证一个类仅有一个实例,并提供一个访问它的全局访问点. Singleton的英文意义是独身,也就是只有一个人,应用在物件导向语言上,通常翻译作单例:单一个实例(Instance).  很多时候,您会需要Singleton模式,例如印表机管理,您希望程式中只能有一个Print Spooler,以避免两个列印动作同时输入至印表机中:例如资料库管理,因为建立连接(Connection)物件会耗用资源,您希望程式中只能有一个 连接物件,所有其它的程式都透过这个物件来连接资料库,以避免连接物件

Design Pattern: Adapter 模式 - Class Adapter

Adapter模式的另一种作法是Class Adapter模式,在这个模式下,Adapter直接继承Adaptee(要引进的新类别),以拥有当中的成员及方法,在C++中的话可以这么作: C++中可以多重继承,但在Java中不行,所以在Java中若要采用Class Adapter,必须作点修改,一方面继承Adaptee,一方面实作Target的介面: 代码的实现是这样的: public class Adapter extends Adaptee implements Target {      /

Design Pattern: Flyweight 模式

学习是分享和合作式的! 转载请注明出处:http://blog.csdn.net/wdzxl198/article/details/10472999: 文章摘自: http://www.riabook.cn/doc/designpattern/: 在 Gof 的书中指出,Flyweight的目的在于运用共享技术,使得一些细粒度的物件可以共享. Flyweight在牛津字典中的解释是"boxer of the lightest class".意思是特轻量级拳击手?其实应该是取"

Design Pattern: Strategy 模式

  学习是分享和合作式的! 转载请注明出处:http://blog.csdn.net/wdzxl198/article/details/9306775: 文章摘自: http://www.riabook.cn/doc/designpattern/: 考虑您要设计一个更换各种符号的工具类TextCharChange,您是否会采用这样的方式: 1: public void replace() { 2: switch(getChangeType()) { 3: case RN_TYPE: 4: rep

Design Pattern: Composite 模式

  学习是分享和合作式的! 转载请注明出处:http://blog.csdn.net/wdzxl198/article/details/9417163: 文章摘自: http://www.riabook.cn/doc/designpattern/: 如果以绘图为例的话,一个文字是一个绘图元件,一个线段是一个绘图元件,而一个长方形也是一个绘图元件,这些绘图元件可以组成一个图片,如果将这个图片也 视作一个绘图元件,则这么递回绘图下去,就可以组合成一个较大的.复杂的图形元件,这样的目的可以使用Comp

Design Pattern: Facade 模式

  学习是分享和合作式的! 转载请注明出处:http://blog.csdn.net/wdzxl198/article/details/10472943: 文章摘自: http://www.riabook.cn/doc/designpattern/: 考虑要撰写一个Web Mail程式,手上已经有一些已经开发好的元件(Component),像是开发Web Mail所需要的SMTP处理类.允许上传附档的FileUpload类,以及Web安全相关的API.其它相关的Package等等. 当拿到一些现