工廠方法模式
前言
在前面部落客寫的文章:設計模式-----簡單工廠模式,發現簡單工廠模式存在一系列問題:
- 工廠類集中了所有執行個體(産品)的建立邏輯,一旦這個工廠不能正常工作,整個系統都會受到影響
- 違背“開放 - 關閉原則”,一旦添加新産品就不得不修改工廠類的邏輯,這樣就會造成工廠邏輯過于複雜
- 簡單工廠模式由于使用了靜态工廠方法,靜态方法不能被繼承和重寫,會造成工廠角色無法形成基于繼承的等級結構
為了解決上述的問題,我們又使用了一種新的設計模式:工廠方法模式
1.介紹
1.1 定義
工廠方法模式,又稱工廠模式、多态工廠模式和虛拟構造器模式,通過定義工廠父類負責定義建立對象的公共接口,而子類則負責生成具體的對象
1.2 主要作用
将類的執行個體化(具體産品的建立)延遲到工廠類的子類(具體工廠)中完成,即由子類來決定應該執行個體化(建立)哪一個類
1.3 解決的問題
工廠一旦需要生産新産品就需要修改工廠類的方法邏輯,違背了“開放 - 關閉原則
- 即簡單工廠模式的缺點
- 之是以可以解決簡單工廠的問題,是因為工廠方法模式把具體産品的建立推遲到工廠類的子類(具體工廠)中,此時工廠類不再負責所有産品的建立,而隻是給出具體工廠必須實作的接口,這樣工廠方法模式在添加新産品的時候就不修改工廠類邏輯而是添加新的工廠子類,符合開放封閉原則,克服了簡單工廠模式中缺點
2.模式原理
2.1 UML類圖
2.2 模式組成
組成(角色) | 關系 | 作用 |
---|---|---|
抽象産品(Product) | 具體産品的父類 | 描述具體産品的公共接口 |
具體産品(Concrete Product) | 抽象産品的子類;工廠類建立的目标類 | 描述生産的具體産品 |
抽象工廠(Creator) | 具體工廠的父類 | 描述具體工廠的公共接口 |
具體工廠(Concrete Creator) | 抽象工廠的子類;被外界調用 | 描述具體工廠;實作FactoryMethod工廠方法建立産品的執行個體 |
2.3 使用步驟
- 建立抽象工廠類,定義具體工廠的公共接口
- 建立抽象産品類 ,定義具體産品的公共接口
- 建立具體産品類(繼承抽象産品類) & 定義生産的具體産品
- 建立具體工廠類(繼承抽象工廠類),定義建立對應具體産品執行個體的方法
- 外界通過調用具體工廠類的方法,進而建立不同具體産品類的執行個體
3.執行個體講解
3.1 執行個體概況
- 背景:小成有一間塑膠加工廠(僅生産A類産品);随着客戶需求的變化,客戶需要生産B類産品
- 沖突:改變原有塑膠加工廠的配置和變化非常困難,假設下一次客戶需要再發生變化,再次改變将增大非常大的成本
- 解決方案:小成決定置辦塑膠分廠B來生産B類産品
3.2 使用步驟
3.2.1:建立抽象工廠類,定義具體工廠的公共接口
abstract class Factory{
public abstract Product Manufacture();
}
3.2.2 建立抽象産品類 ,定義具體産品的公共接口
abstract class Product{
public abstract void Show();
}
3.2.3 建立具體産品類(繼承抽象産品類), 定義生産的具體産品
//具體産品A類
class ProductA extends Product{
@Override
public void Show() {
System.out.println("生産出了産品A");
}
}
//具體産品B類
class ProductB extends Product{
@Override
public void Show() {
System.out.println("生産出了産品B");
}
}
3.2.4 建立具體工廠類(繼承抽象工廠類),定義建立對應具體産品執行個體的方法
//工廠A類 - 生産A類産品
class FactoryA extends Factory{
@Override
public Product Manufacture() {
return new ProductA();
}
}
//工廠B類 - 生産B類産品
class FactoryB extends Factory{
@Override
public Product Manufacture() {
return new ProductB();
}
}
3.2.5 外界通過調用具體工廠類的方法,進而建立不同*具體産品類的執行個體
//生産工作流程
public class FactoryPattern {
public static void main(String[] args){
//客戶要産品A
FactoryA mFactoryA = new FactoryA();
mFactoryA.Manufacture().Show();
//客戶要産品B
FactoryB mFactoryB = new FactoryB();
mFactoryB.Manufacture().Show();
}
}
結果:
生産出了産品A
生産出了産品B
4.優點
-
更符合開-閉原則
新增一種産品時,隻需要增加相應的具體産品類和相應的工廠子類即可
簡單工廠模式需要修改工廠類的判斷邏輯
-
符合單一職責原則
每個具體工廠類隻負責建立對應的産品
簡單工廠中的工廠類存在複雜的switch邏輯判斷
- 不使用靜态工廠方法,可以形成基于繼承的等級結構
簡單工廠模式的工廠類使用靜态工廠方法
總結:
工廠模式可以說是簡單工廠模式的進一步抽象和拓展,在保留了簡單工廠的封裝優點的同時,讓擴充變得簡單,讓繼承變得可行,增加了多态性的展現
5.缺點
- 添加新産品時,除了增加新産品類外,還要提供與之對應的具體工廠類,系統類的個數将成對增加,在一定程度上增加了系統的複雜度;同時,有更多的類需要編譯和運作,會給系統帶來一些額外的開銷
- 由于考慮到系統的可擴充性,需要引入抽象層,在用戶端代碼中均使用抽象層進行定義,增加了系統的抽象性和了解難度,且在實作時可能需要用到DOM、反射等技術,增加了系統的實作難度
- 雖然保證了工廠方法内的對修改關閉,但對于使用工廠方法的類,如果要更換另外一種産品,仍然需要修改執行個體化的具體工廠類
- 一個具體工廠隻能建立一種具體産品
6.應用場景
-
當一個類不知道它所需要的對象的類時
在工廠方法模式中,用戶端不需要知道具體産品類的類名,隻需要知道所對應的工廠即可
-
當一個類希望通過其子類來指定建立對象時
在工廠方法模式中,對于抽象工廠類隻需要提供一個建立産品的接口,而由其子類來确定具體要建立的對象,利用面向對象的多态性和裡氏代換原則,在程式運作時,子類對象将覆寫父類對象,進而使得系統更容易擴充
- 将建立對象的任務委托給多個工廠子類中的某一個,用戶端在使用時可以無須關心是哪一個工廠子類建立産品子類,需要時再動态指定,可将具體工廠類的類名存儲在配置檔案或資料庫中