物件的克隆——原型模式(四)

Liuwei-Sunny發表於2012-04-03

7.5 原型管理器的引入和實現

      原型管理器(Prototype Manager)是將多個原型物件儲存在一個集合中供客戶端使用,它是一個專門負責克隆物件的工廠,其中定義了一個集合用於儲存原型物件,如果需要某個原型物件的一個克隆,可以通過複製集合中對應的原型物件來獲得。在原型管理器中針對抽象原型類進行程式設計,以便擴充套件。其結構如圖7-8所示:

                             

7-8 帶原型管理器的原型模式

      下面通過模擬一個簡單的公文管理器來介紹原型管理器的設計與實現:

Sunny軟體公司在日常辦公中有許多公文需要建立、遞交和審批,例如《可行性分析報告》、《立項建議書》、《軟體需求規格說明書》、《專案進展報告》等,為了提高工作效率,在OA系統中為各類公文均建立了模板,使用者可以通過這些模板快速建立新的公文,這些公文模板需要統一進行管理,系統根據使用者請求的不同生成不同的新公文。

       我們使用帶原型管理器的原型模式實現公文管理器的設計,其結構如圖7-9所示:

 

7-9 公文管理器結構圖

      以下是實現該功能的一些核心程式碼,考慮到程式碼的可讀性,我們對所有的類都進行了簡化:

import java.util.*;

 

//抽象公文介面,也可定義為抽象類,提供clone()方法的實現,將業務方法宣告為抽象方法

interface OfficialDocument extends  Cloneable

{

       public  OfficialDocument clone();

       public  void display();

}

 

//可行性分析報告(Feasibility Analysis Report)

class FAR implements OfficialDocument

{

       public  OfficialDocument clone()

      {

              OfficialDocument  far = null;

              try

              {

                     far  = (OfficialDocument)super.clone();

              }

              catch(CloneNotSupportedException  e)

              {

                      System.out.println("不支援複製!");

              }

              return  far;

       }

      

       public  void display()

       {

              System.out.println("《可行性分析報告》");

       }

}

 

//軟體需求規格說明書(Software Requirements Specification)

class SRS implements OfficialDocument

{

       public  OfficialDocument clone()

       {

              OfficialDocument  srs = null;

              try

              {

                     srs  = (OfficialDocument)super.clone();

              }

              catch(CloneNotSupportedException  e)

              { 

                     System.out.println("不支援複製!");

              }

              return  srs;

       }

      

       public  void display()

       {

              System.out.println("《軟體需求規格說明書》");

       }

}

 

//原型管理器(使用餓漢式單例實現)

class  PrototypeManager

{

       //定義一個Hashtable,用於儲存原型物件

       private Hashtable ht=new Hashtable();

       private static PrototypeManager pm =  new PrototypeManager();

      

       //Hashtable增加公文物件   

     private  PrototypeManager()

     {

              ht.put("far",new  FAR());

              ht.put("srs",new  SRS());               

     }

  

     //增加新的公文物件

       public void addOfficialDocument(String  key,OfficialDocument doc)

       {

              ht.put(key,doc);

       }

 

       //通過淺克隆獲取新的公文物件

       public OfficialDocument  getOfficialDocument(String key)

       {

              return  ((OfficialDocument)ht.get(key)).clone();

       }

      

       public static PrototypeManager  getPrototypeManager()

       {

              return pm;

       }

}

      客戶端程式碼如下所示:

class Client

{

       public  static void main(String args[])

       {

              //獲取原型管理器物件

              PrototypeManager pm =  PrototypeManager.getPrototypeManager();  

             

              OfficialDocument  doc1,doc2,doc3,doc4;

             

              doc1  = pm.getOfficialDocument("far");

              doc1.display();

              doc2  = pm.getOfficialDocument("far");

              doc2.display();

              System.out.println(doc1  == doc2);

             

              doc3  = pm.getOfficialDocument("srs");

              doc3.display();

              doc4  = pm.getOfficialDocument("srs");

              doc4.display();

              System.out.println(doc3  == doc4);

       }

}

      編譯並執行程式,輸出結果如下:

《可行性分析報告》

《可行性分析報告》

false

《軟體需求規格說明書》

《軟體需求規格說明書》

false

      在PrototypeManager中定義了一個Hashtable型別的集合物件,使用“鍵值對”來儲存原型物件,客戶端可以通過Key(如“far”或“srs”)來獲取對應原型物件的克隆物件。PrototypeManager類提供了類似工廠方法的getOfficialDocument()方法用於返回一個克隆物件。在本例項程式碼中,我們將PrototypeManager設計為單例類,使用餓漢式單例實現,確保系統中有且僅有一個PrototypeManager物件,有利於節省系統資源,並可以更好地對原型管理器物件進行控制。

 

思考

如果需要增加一種新型別的公文,如《專案進展報告》(Project    Progress Report, PPR),公文管理器系統原始碼如何修改,動手實踐你的修改方案。

7.6 原型模式總結

      原型模式作為一種快速建立大量相同或相似物件的方式,在軟體開發中應用較為廣泛,很多軟體提供的複製(Ctrl + C)和貼上(Ctrl + V)操作就是原型模式的典型應用,下面對該模式的使用效果和適用情況進行簡單的總結。

1.主要優點

      原型模式的主要優點如下:

(1) 當建立新的物件例項較為複雜時,使用原型模式可以簡化物件的建立過程,通過複製一個已有例項可以提高新例項的建立效率。

(2) 擴充套件性較好,由於在原型模式中提供了抽象原型類,在客戶端可以針對抽象原型類進行程式設計,而將具體原型類寫在配置檔案中,增加或減少產品類對原有系統都沒有任何影響。

(3) 原型模式提供了簡化的建立結構,工廠方法模式常常需要有一個與產品類等級結構相同的工廠等級結構,而原型模式就不需要這樣,原型模式中產品的複製是通過封裝在原型類中的克隆方法實現的,無須專門的工廠類來建立產品。

(4) 可以使用深克隆的方式儲存物件的狀態,使用原型模式將物件複製一份並將其狀態儲存起來,以便在需要的時候使用(如恢復到某一歷史狀態),可輔助實現撤銷操作。

2.主要缺點

      原型模式的主要缺點如下:

(1) 需要為每一個類配備一個克隆方法,而且該克隆方法位於一個類的內部,當對已有的類進行改造時,需要修改原始碼,違背了“開閉原則”。

(2) 在實現深克隆時需要編寫較為複雜的程式碼,而且當物件之間存在多重的巢狀引用時,為了實現深克隆,每一層物件對應的類都必須支援深克隆,實現起來可能會比較麻煩。

3.適用場景

        在以下情況下可以考慮使用原型模式:

(1) 建立新物件成本較大(如初始化需要佔用較長的時間,佔用太多的CPU資源或網路資源),新的物件可以通過原型模式對已有物件進行復制來獲得,如果是相似物件,則可以對其成員變數稍作修改。

(2) 如果系統要儲存物件的狀態,而物件的狀態變化很小,或者物件本身佔用記憶體較少時,可以使用原型模式配合備忘錄模式來實現。

(3) 需要避免使用分層次的工廠類來建立分層次的物件,並且類的例項物件只有一個或很少的幾個組合狀態,通過複製原型物件得到新例項可能比使用建構函式建立一個新例項更加方便。

 

練習

設計並實現一個客戶類Customer,其中包含一個名為客戶地址的成員變數,客戶地址的型別為Address,用淺克隆和深克隆分別實現Customer物件的複製並比較這兩種克隆方式的異同。

【作者:劉偉http://blog.csdn.net/lovelion

相關文章