大家好,又見面了,我是你們的朋友全棧君。
概述
工廠模式(Factory Pattern)屬于建立型模式,它提供了一種建立對象的最佳方式。
在工廠模式中,我們在建立對象時不會對用戶端暴露建立邏輯,并且是通過使用一個共同的接口來指向新建立的對象。
工廠模式旨在與解決接口實作類選擇這一類問題,讓執行個體建立的代碼使用執行個體的方法解耦。
當我們需要根據不同的明确條件下建立不同的執行個體的時候,就可以使用工廠模式。
工廠模式分為三類:
- 工廠方法模式:一個工廠生産固定的一個類。
- 簡單/靜态工廠模式:一個工廠生産固定種類的多個類。
- 抽象工廠模式:一個抽象工廠生産一
一、工廠方法模式
假設我們有一個導出報表的抽象類:
/**
* 檔案導出接口
*/
public abstract class Exporter {
void export();
}
複制
他現在有一個Excel導出實作類:
/**
* Excel導出實作類
*/
public class ExcelExporter extend Exporter{
private String modelPath;
private String fileName;
@Override
public void export() {
System.out.println("導出Excel:"+"模闆路徑:"+ modelPath +"檔案名:" + fileName);
}
public ExcelExporter(String modelPath, String fileName) {
this.modelPath = modelPath;
this.fileName = fileName;
}
}
複制
現在我們需要在一個方法裡去調用它,讓客戶可以導出報表:
//從配置中讀取模闆路徑
String modelPath = Config.getExcelModelPath();
//擷取檔案名
String fileName = name + Config.getExcelLastName();
ExcelExporter ee = new ExcelExporter(modelPath, fileName);
//一些其他業務邏輯
... ...
ee.export();
複制
我們在很多方法都需要調用這個類,但是每次使用都要寫那麼多行代碼,實在太麻煩,而且萬一忽然modelPath或者fileName這些參數要改,那工程量也很讓人頭痛。
是以我們可以把擷取對象的操作提出來,把讀取配置路徑等方法都單獨提出來,最後統一放到一個工廠類裡:
/**
* Excel檔案導出實作類的工廠
*/
public class ExcelExporterFactory {
public String getExcelLastName(){
return Config.getExcelLastName();
}
public String getModePath(){
return Config.getExcelModelPath();
}
public ExcelExporter getExporter(String type) {
return new ExcelExporter(getModePath(),getExcelLastName());
}
}
複制
最後使用的時候不需要在意執行個體化的過程,隻需要調用方法擷取新對象就行了:
ExcelExporterFactory factory = new ExcelExporterFactory();
factory.getExcelExporter().export();
複制
值得一提的是,由于工廠的特殊性,它大多數情況下都是單例的。
不難發現,工廠方法模式有以下優點:
- 1:用戶端不需要在負責對象的建立,明确了各個類的職責;
- 2:如果有新的對象增加,隻需要增加一個具體的類和具體的工廠類即可;
- 3:不會影響已有的代碼,後期維護容易,增強系統的擴充性。
二、簡單/靜态工廠
工廠方法模式确實好,但是有時候我們需要用工廠生産的往往隻有特定的幾個類,其他的直接new就可以了。這種情況下在為每一個類單獨建立一個工廠類太過麻煩,為此我們讓一個工廠去生産固定的那幾種類,這就是簡單/靜态工廠。
假設我們目前隻需要導出Excel和word類型的報表,我們在上一個例子的基礎上再加一WordExporter實作類:
/**
* Excel導出實作類
*/
public class WordExporter extend Exporter {
private String modelPath;
private String fileName;
@Override
public void export() {
System.out.println("導出Word!");
}
public WordExporter(String modelPath, String fileName) {
this.modelPath = modelPath;
this.fileName = fileName;
}
}
複制
然後我們改造一下原本的ExcelExporterFactory,讓他也能生産WordExporter:
/**
* 檔案導出實作類的簡單工廠
*/
public class ExporterFactory {
public String getExcelLastName(){
return Config.getExcelLastName();
}
public String getModePath(){
return Config.getExcelModelPath();
}
public Exporter getExporter(String type) {
//根據條件傳回對應的執行個體
if ("word".equals(type)) {
return new WordExporter(getModePath(),getExcelLastName());
} else if ("excel".equals(type)) {
return new ExcelExporter(getModePath(),getExcelLastName());
}else {
throw new RuntimeException("導出類型不存在!");
}
}
}
複制
當我們要調用的時候,直接通過工廠調用就可以了:
ExporterFactory factory = new ExporterFactory();
factory.getExcelExporter(type).export();
複制
這個就是簡單工廠。
在簡單工廠的基礎上,我們不難看出,現在的ExporterFactory總是隻能生産固定的那幾種類,那麼其實調用
getExporter()
去擷取實作類的時候根本沒必要new一個新工廠。
于是我們将這個工程裡的所有方法都變成靜态方法,調用的時候就很友善了:
ExportService es = ExporterFactory.getExporter(type);
複制
這個就是靜态工廠。
三、抽象工廠模式
簡單工廠對工廠方法做了減法,簡化了代碼結構,但是簡單工廠違背了開閉原則,如果要添加新的産品,就需要修改工廠類代碼。而傳統的工廠方法模式,如果有很多産品的情況下又會建立過多的工廠類。
為此,我們對工廠方法模式做加法,就有了抽象工廠模式:由頂層的抽象工廠提供生産産品的接口,具體的生産過程由繼承了抽象工廠的子工廠去實作。
舉個例子:
根據上文,我們現在有了Exporter接口,和兩個實作類ExcelExporter和WordExporter,現在我們有了新的需求:
導出的報表要分成兩種類型:有資料的表格和沒有資料的表格。(empty)
1.産品的抽象
我們先對産品進行抽象:
Exporter這個類不管是否有資料,都需要導出方法
export()
,然後根據表格是否有資料,還需要一個方法
empty()
。
我們将其分為由原本的ExcelExporter和WordExporter也變成抽象類,隻實作各種的
export()
方法,然後再針對ExcelExporter和WordExporter再拆分,得到無資料表格類EmptyExcelExporter,EmptyWordExporter,有資料表格類FullExcelExporter,FullWordExporter。
2.工廠的抽象
由于産品的層級變成了三層,原本用于生産WordExporter和ExcelExporter的工廠ExporterFactory也要進行拆分。
将ExporterFactory變為接口,裡面規定了
getExcelExporter()
和
getWordExporter()
兩個接口方法,然後由EmptyExporterFactory還有FullExporterFactory工廠去
不難看出,抽象工廠通過多了一層抽象,減少了工廠類的數量,但是當要添加一類産品,比如加一個導出PDF類,同樣要修改ExporterFactory及其實作類。
釋出者:全棧程式員棧長,轉載請注明出處:https://javaforall.cn/170790.html原文連結:https://javaforall.cn