工廠方法模式

工廠方法模式是類的創建模式,又叫做虛擬構造子(Virtual Constructor)模式或者多態性工廠(Polymorphic Factory)模式。

  工廠方法模式的用意是定義一個創建產品對象的工廠接口,將實際創建工作推遲到子類中。

那麼工廠方法模式是在什麼場景下使用呢,下面就以本人的理解舉例說明:

  相信很多人都做過導入導出功能,就拿導出功能來說。有這麼一個需求:XX系統需要支持對數據庫中的員工薪資進行導出,並且支持多種格式如:HTML、CSV、PDF等,每種格式導出的結構有所不同,比如:財務跟其他人對導出薪資的HTML格式要求可能會不一樣,因爲財務可能需要特定的格式方便覈算或其他用途。

  如果使用簡單工廠模式,則工廠類必定過於臃腫。因爲簡單工廠模式只有一個工廠類,它需要處理所有的創建的邏輯。假如以上需求暫時只支持3種導出的格式以及2種導出的結構,那工廠類則需要6個if else來創建6種不同的類型。如果日後需求不斷增加,則後果不堪設想。

  這時候就需要工廠方法模式來處理以上需求。在工廠方法模式中,核心的工廠類不再負責所有的對象的創建,而是將具體創建的工作交給子類去做。這個核心類則搖身一變,成爲了一個抽象工廠角色,僅負責給出具體工廠子類必須實現的接口,而不接觸哪一個類應當被實例化這種細節。

  這種進一步抽象化的結果,使這種工廠方法模式可以用來允許系統在不修改具體工廠角色的情況下引進新的產品,這一特點無疑使得工廠方法模式具有超過簡單工廠模式的優越性。下面就針對以上需求設計UML圖:

 

從上圖可以看出,這個使用的工廠方法模式的系統涉及到以下角色:

 

  抽象工廠(ExportFactory)角色:擔任這個角色的是工廠方法模式的核心,任何在模式中創建對象的工廠類必須實現這個接口。在實際的系統中,這個角色也常常使用抽象類實現。

  具體工廠(ExportHtmlFactory、ExportPdfFactory)角色:擔任這個角色的是實現了抽象工廠接口的具體JAVA類。具體工廠角色含有與業務密切相關的邏輯,並且受到使用者的調用以創建導出類(如:ExportStandardHtmlFile)。

  抽象導出(ExportFile)角色:工廠方法模式所創建的對象的超類,也就是所有導出類的共同父類或共同擁有的接口。在實際的系統中,這個角色也常常使用抽象類實現。

  具體導出(ExportStandardHtmlFile等)角色:這個角色實現了抽象導出(ExportFile)角色所聲明的接口,工廠方法模式所創建的每一個對象都是某個具體導出角色的實例。

源代碼

  首先是抽象工廠角色源代碼。它聲明瞭一個工廠方法,要求所有的具體工廠角色都實現這個工廠方法。參數type表示導出的格式是哪一種結構,如:導出HTML格式有兩種結構,一種是標準結構,一種是財務需要的結構

  1. package com.bankht.factoryMethod;  
  2.   
  3. /** 
  4.  * @author: 特種兵—AK47 
  5.  * @創建時間:2012-6-19 下午02:53:10 
  6.  *  
  7.  * @類說明 :抽象工廠角色 
  8.  */  
  9. public interface ExportFactory {  
  10.     public ExportFile factory(String type);  
  11. }  


具體工廠角色類源代碼:

  1. package com.bankht.factoryMethod;  
  2.   
  3. /** 
  4.  * @author: 特種兵—AK47 
  5.  * @創建時間:2012-6-19 下午02:54:54 
  6.  *  
  7.  * @類說明 :具體工廠角色類 
  8.  */  
  9. public class ExportHtmlFactory implements ExportFactory {  
  10.   
  11.     @Override  
  12.     public ExportFile factory(String type) {  
  13.         // TODO Auto-generated method stub  
  14.         if ("standard".equals(type)) {  
  15.   
  16.             return new ExportStandardHtmlFile();  
  17.   
  18.         } else if ("financial".equals(type)) {  
  19.   
  20.             return new ExportFinancialHtmlFile();  
  21.   
  22.         } else {  
  23.             throw new RuntimeException("沒有找到對象");  
  24.         }  
  25.     }  
  26.   
  27. }  


 

  1. package com.bankht.factoryMethod;  
  2.   
  3. /** 
  4.  * @author: 特種兵—AK47 
  5.  * @創建時間:2012-6-19 下午02:55:04 
  6.  *  
  7.  * @類說明 :具體工廠角色類 
  8.  */  
  9. public class ExportPdfFactory implements ExportFactory {  
  10.   
  11.     @Override  
  12.     public ExportFile factory(String type) {  
  13.         if ("standard".equals(type)) {  
  14.   
  15.             return new ExportStandardHtmlFile();  
  16.   
  17.         } else if ("financial".equals(type)) {  
  18.   
  19.             return new ExportFinancialHtmlFile();  
  20.   
  21.         } else {  
  22.             throw new RuntimeException("沒有找到對象");  
  23.         }  
  24.     }  
  25.   
  26. }  


抽象導出角色類源代碼:

  1. package com.bankht.factoryMethod;  
  2.   
  3. /** 
  4.  * @author: 特種兵—AK47 
  5.  * @創建時間:2012-6-19 下午02:55:47 
  6.  *  
  7.  * @類說明 :抽象導出文件類 
  8.  */  
  9. public interface ExportFile {  
  10.     public boolean export(String data);  
  11. }  


具體導出角色類源代碼,通常情況下這個類會有複雜的業務邏輯。

財務:

  1. package com.bankht.factoryMethod;  
  2.   
  3. /** 
  4.  * @author: 特種兵—AK47 
  5.  * @創建時間:2012-6-19 下午02:54:54 
  6.  *  
  7.  * @類說明 :導出財務版HTML文件 
  8.  */  
  9. public class ExportFinancialHtmlFile implements ExportFile {  
  10.   
  11.     @Override  
  12.     public boolean export(String data) {  
  13.         // TODO Auto-generated method stub  
  14.         /** 
  15.          * 業務邏輯 
  16.          */  
  17.         System.out.println("導出財務版HTML文件");  
  18.         return true;  
  19.     }  
  20.   
  21. }  


 

  1. package com.bankht.factoryMethod;  
  2.   
  3. /** 
  4.  * @author: 特種兵—AK47 
  5.  * @創建時間:2012-6-19 下午02:54:54 
  6.  *  
  7.  * @類說明 :導出財務版PDF文件 
  8.  */  
  9. public class ExportFinancialPdfFile implements ExportFile {  
  10.   
  11.     @Override  
  12.     public boolean export(String data) {  
  13.         // TODO Auto-generated method stub  
  14.         /** 
  15.          * 業務邏輯 
  16.          */  
  17.         System.out.println("導出財務版PDF文件");  
  18.         return true;  
  19.     }  
  20.   
  21. }  


普通:

  1. package com.bankht.factoryMethod;  
  2.   
  3. /** 
  4.  * @author: 特種兵—AK47 
  5.  * @創建時間:2012-6-19 下午02:54:54 
  6.  *  
  7.  * @類說明 :導出標準HTML文件 
  8.  */  
  9. public class ExportStandardHtmlFile implements ExportFile {  
  10.   
  11.     @Override  
  12.     public boolean export(String data) {  
  13.         // TODO Auto-generated method stub  
  14.         /** 
  15.          * 業務邏輯 
  16.          */  
  17.         System.out.println("導出標準HTML文件");  
  18.         return true;  
  19.     }  
  20.   
  21. }  


 

  1. package com.bankht.factoryMethod;  
  2.   
  3. /** 
  4.  * @author: 特種兵—AK47 
  5.  * @創建時間:2012-6-19 下午02:54:54 
  6.  *  
  7.  * @類說明 :導出標準PDF文件 
  8.  */  
  9. public class ExportStandardPdfFile implements ExportFile {  
  10.   
  11.     @Override  
  12.     public boolean export(String data) {  
  13.         // TODO Auto-generated method stub  
  14.         /** 
  15.          * 業務邏輯 
  16.          */  
  17.         System.out.println("導出標準PDF文件");  
  18.         return true;  
  19.     }  
  20.   
  21. }  


 

客戶端角色類源代碼:

  1. package com.bankht.factoryMethod;  
  2.   
  3. import org.junit.Test;  
  4.   
  5. /** 
  6.  * @author: 特種兵—AK47 
  7.  * @創建時間:2012-6-19 下午02:59:25 
  8.  *  
  9.  * @類說明 :測試工廠方法模式類 
  10.  */  
  11. public class TestFactoryMethod {  
  12.   
  13.     @Test  
  14.     public void testFactoryMethod() {  
  15.         String data = "";  
  16.         ExportFactory exportFactory = new ExportHtmlFactory();  
  17.         ExportFile ef = exportFactory.factory("financial");  
  18.         ef.export(data);  
  19.     }  
  20.   
  21. }  


工廠方法模式的活動序列圖


  客戶端創建ExportHtmlFactory對象,這時客戶端所持有變量的靜態類型爲ExportFactory,而實際類型爲ExportHtmlFactory。然後客戶端調用ExportHtmlFactory對象的工廠方法factory(),接着後者調用ExportFinancialHtmlFile的構造子創建出導出對象。

工廠方法模式和簡單工廠模式

  工廠方法模式和簡單工廠模式在結構上的不同很明顯。工廠方法模式的核心是一個抽象工廠類,而簡單工廠模式把核心放在一個具體類上。
  工廠方法模式退化後可以變得很像簡單工廠模式。設想如果非常確定一個系統只需要一個具體工廠類,那麼不妨把抽象工廠類合併到具體工廠類中去。由於只有一個具體工廠類,所以不妨將工廠方法改爲靜態方法,這時候就得到了簡單工廠模式。

  如果系統需要加入一個新的導出類型,那麼所需要的就是向系統中加入一個這個導出類以及所對應的工廠類。沒有必要修改客戶端,也沒有必要修改抽象工廠角色或者其他已有的具體工廠角色。對於增加新的導出類型而言,這個系統完全支持“開-閉原則”。
  

完結

  一個應用系統是由多人開發的,導出的功能是你實現的,但是使用者(調用這個方法的人)可能卻是其他人。這時候你應該設計的足夠靈活並儘可能降低兩者之間的耦合度,當你修改或增加一個新的功能時,使用者不需要修改任何地方。假如你的設計不夠靈活,那麼將無法面對客戶多變的需求。可能一個極小的需求變更,都會使你的代碼結構發生改變,並導致其他使用你所提供的接口的人都要修改他們的代碼。牽一處而動全身,這就使得日後這個系統將難以維護

發佈了128 篇原創文章 · 獲贊 14 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章