閱讀674 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Design Pattern: Prototype 模式

  學習是分享和合作式的!

轉載請注明出處:https://blog.csdn.net/wdzxl198/article/details/9271773

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

您從圖書館的期刊從發現了幾篇您感興趣的文章,由於這是圖書館的書,您不可以直接在書中作記號或寫字,所以您將當中您所感興趣的幾個主題影印出來,這下子您就可在影印的文章上畫記重點。
Prototype模式的作用有些類似上麵的描述,您在父類別中定義一個clone()方法,而在子類別中重新定義它,當客戶端對於所產生的物件有興趣並想加以利用,而您又不想破壞原來的物件,您可以產生一個物件的複本給它。
Prototype具有展示的意味,就像是展覽會上的原型車款,當您對某個車款感興趣時,您可以購買相同款示的車,而不是車展上的車。
在軟體設計上的例子會更清楚的說明為何要進行物件複製,假設您要設計一個室內設計軟體,軟體中有一個展示家具的工具列,您隻要點選工具列就可以產生一個家 具複本,例如一張椅子或桌子,您可以拖曳這個複製的物件至設計圖中,隨時改變它的位置、顏色等等,當您改變設計圖中的物件時,工具列上的原型工具列是不會 跟著一起改變的,這個道理是無需解釋的。
下麵的 UML 類別圖表示了上述的簡單概念:

Prototype

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模式的類別結構圖:

Prototype

在 Gof 的設計模式書中給出一個原型模式的應用:一個通用的圖型編輯器 Framework。在這個 Framework中有一個工具列,您可以在上麵選擇音樂符號以加入樂譜中,並可以隨時調整音樂符號的位置等等。
圖型編輯器Framework是通用的,然而它並不知道這些音樂符號的型態,有人或許會想到繼承圖型編輯器Framework來為每個音樂符號設計一個框 架子類別,但由於音樂符號的種類很多,這會產生相當多的子類別,為了避免這種情況,可以透過Prototype模式來減少子類別的數目,可以設計出以下的 結構:

Prototype

依照這個結構,圖型編輯器的Framework可以獨立於要套用的特定類別之外,雖然不知道被複製傳回的對象型態是什麼,但總可以按照 Graphics所定義的介麵來操作這些物件。

Edit by Atlas

Time 2013/7/8 14:41

最後更新:2017-04-03 16:48:33

  上一篇:go C# 網絡編程之套接字編程基礎知識
  下一篇:go python控製語句