1. 程式人生 > >《JAVA與模式》之工廠方法模式

《JAVA與模式》之工廠方法模式

ktv bwt dex zoho ase lba dmg bps rpc

在閻宏博士的《JAVA與模式》一書中開頭是這樣描述工廠方法模式的:

  工廠方法模式是類的創建模式,又叫做虛擬構造子(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格式有兩種結構,一種是標準結構,一種是財務需要的結構。

public interface ExportFactory {
public ExportFile factory(String type);
}

  具體工廠角色類源代碼:

技術分享
public class ExportHtmlFactory implements ExportFactory{

@Override
public ExportFile factory(String type) {
// TODO Auto-generated method stub
if("standard".equals(type)){

return new ExportStandardHtmlFile();

}else if("financial".equals(type)){

return new ExportFinancialHtmlFile();

}else{
throw new RuntimeException("沒有找到對象");
}
}

}
技術分享 技術分享
public class ExportPdfFactory implements ExportFactory {

@Override
public ExportFile factory(String type) {
// TODO Auto-generated method stub
if("standard".equals(type)){

return new ExportStandardPdfFile();

}else if("financial".equals(type)){

return new ExportFinancialPdfFile();

}else{
throw new RuntimeException("沒有找到對象");
}
}

}
技術分享

  抽象導出角色類源代碼:

public interface ExportFile {
public boolean export(String data);
}

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

技術分享
public class ExportFinancialHtmlFile implements ExportFile{

@Override
public boolean export(String data) {
// TODO Auto-generated method stub
/**
* 業務邏輯
*/
System.out.println("導出財務版HTML文件");
return true;
}

}
技術分享 技術分享
public class ExportFinancialPdfFile implements ExportFile{

@Override
public boolean export(String data) {
// TODO Auto-generated method stub
/**
* 業務邏輯
*/
System.out.println("導出財務版PDF文件");
return true;
}

}
技術分享 技術分享
public class ExportStandardHtmlFile implements ExportFile{

@Override
public boolean export(String data) {
// TODO Auto-generated method stub
/**
* 業務邏輯
*/
System.out.println("導出標準HTML文件");
return true;
}

}
技術分享 技術分享
public class ExportStandardPdfFile implements ExportFile {

@Override
public boolean export(String data) {
// TODO Auto-generated method stub
/**
* 業務邏輯
*/
System.out.println("導出標準PDF文件");
return true;
}

}
技術分享

客戶端角色類源代碼:

技術分享
public class Test {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String data = "";
ExportFactory exportFactory = new ExportHtmlFactory();
ExportFile ef = exportFactory.factory("financial");
ef.export(data);
}

}
技術分享

工廠方法模式的活動序列圖
技術分享

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

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

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

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

完結

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

《JAVA與模式》之工廠方法模式