軟體設計

工廠方法與抽象工廠的差異

GoF 工廠方法將單一物件的具體型別決定交給子類別,抽象工廠則會一起建立相關物件產品族。本文以 Swift 範例比較兩種模式的意圖與選擇依據。

閱讀 3 分鐘
工廠方法與抽象工廠的差異 封面圖

學習設計模式時,總有一個讓人卡住的階段。

那就是工廠方法 vs 抽象工廠。兩者名稱相近,也都會「代替你建立物件」,很容易混淆。

這也是面試常見題目,所以我在本文一次整理好了。

先講重點。工廠方法是把物件要建立成哪個類別交給子類別決定;抽象工廠則會完整建立彼此相關的多個物件(產品族)。

static func make 這種替建立流程命名的靜態工廠,和 GoF 工廠方法是不同的概念。如果想了解實務上的 API 設計,建議先將它和 Swift 靜態工廠方法 區分開來。

一個,還是一整組,這就是最大的差異。

什麼是工廠方法?

工廠方法是將建立物件的責任,從上層類別交給子類別的模式。

上層類別只定義「建立按鈕」,至於要建立哪種按鈕則由子類別決定。

直接看程式碼會更快理解。

protocol Button { func render() }

class Dialog {
    // 工廠方法:由子類別決定要建立什麼
    func createButton() -> Button { fatalError("在子類別中實作") }

    func render() {
        let button = createButton()
        button.render()
    }
}

class IOSDialog: Dialog {
    override func createButton() -> Button { IOSButton() }
}

Dialog 不需要知道自己使用哪種按鈕。新增平台時,只要再建立一個子類別即可。

核心在於繼承。這是透過子類別化替換建立位置的結構。


抽象工廠有什麼不同?

抽象工廠是將相關物件綁成一組來建立的模式。

它負責的不是單一按鈕,而是按鈕、核取方塊、捲軸等必須一起使用的物件。

protocol GUIFactory {
    func createButton() -> Button
    func createCheckbox() -> Checkbox
}

class IOSFactory: GUIFactory {
    func createButton() -> Button { IOSButton() }
    func createCheckbox() -> Checkbox { IOSCheckbox() }
}

class MacFactory: GUIFactory {
    func createButton() -> Button { MacButton() }
    func createCheckbox() -> Checkbox { MacCheckbox() }
}

重點是一致性。使用 iOS 工廠時,按鈕和核取方塊都會採用 iOS 樣式,不會發生 iOS 按鈕混入 Mac 核取方塊的問題。

抽象工廠通常會從外部注入工廠物件後使用。它不是靠繼承,而是靠組合運作。

不論是 iOS 還是 Mac,只要替換工廠,整組產品就會一起改變
不論是 iOS 還是 Mac,只要替換工廠,整組產品就會一起改變

工廠方法以繼承解決「要建立什麼」,

抽象工廠則以組合解決「要建立哪一組」。


一覽工廠方法與抽象工廠的差異

只用文字說明容易混淆,所以整理成表格。

分類 工廠方法 抽象工廠
目的 委派建立單一物件 建立相關物件族
基礎 繼承(子類別化) 組合(組成)
建立內容 一種產品 多種產品(產品族)
擴充方式 新增子類別 新增工廠
常見範例 createButton() 完整 GUIFactory

有趣的是,抽象工廠內部常常其實是由工廠方法組成。與其說兩者互相競爭,不如看成規模不同的模式。


何時使用,何時避免?

實務上的判斷標準其實比想像中簡單。

  • 如果只會建立一種物件,工廠方法就足夠了。硬是建立工廠介面,反而是過度設計。
  • 如果有兩種以上的物件必須一起運作,請考慮抽象工廠。
  • 如果產品族未來看來不會增加,直接使用條件分支有時反而更好。
情境 判斷
要建立的產品只有一個 工廠方法
產品會綁成一組運作 抽象工廠
產品族經常增加 抽象工廠
只需 2~3 個分支 不使用模式,採單純分支

模式不是目的,而是工具。對不會擴充的程式碼預先加入抽象化,只會讓程式更難閱讀。

模式只是工具,等真正需要時再使用也不遲
模式只是工具,等真正需要時再使用也不遲

面試時會這樣問

Q. 請說明工廠方法與抽象工廠的差異。 A. 工廠方法是將單一物件的建立委派給子類別的繼承型模式。抽象工廠則是以組合為基礎,一致地建立相關物件族。核心差異在於建立一個物件,還是一整組物件。

Q. 抽象工廠中會使用工廠方法嗎? A. 會,而且很常見。抽象工廠的各個建立方法,往往會在內部以工廠方法的形式實作。兩者不是對立概念,而是處理範圍不同的模式。

現在只要看到這兩種模式的名稱,就能想起「一個,還是一整組」,就算掌握重點了。面試前再快速讀一次本文,應該會更有把握。