你是否曾經把 App 畫面主題從淺色整套切換成深色?
如果逐一替換按鈕和標籤的顏色,總會漏掉某個地方。很容易出現按鈕是黑色背景,標籤卻還是白色背景的問題。
這時 Swift 的抽象工廠模式就很適合。把相關物件綁成一組,再整組替換。
修改單一物件建立位置的模式,和建立整個產品族群的模式,適用範圍不同。想先釐清界線,請一併參考 工廠方法 vs 抽象工廠的差異。
本文將整理抽象工廠模式究竟解決什麼問題、如何用 Swift 程式碼一次替換相關物件,以及何時適合或不適合使用。
什麼是抽象工廠模式?
用一句話回答就是:
依情況整個替換一座工廠,而這座工廠會將必須相容的物件成組建立。
核心是「必須一起使用的物件」。深色主題的按鈕和淺色主題的背景混在一起,就會造成問題。
抽象工廠能避免這類組合錯誤。
選定一座工廠後,它產出的零件就會自動互相搭配。選擇淺色工廠,就會得到淺色按鈕、淺色標籤和淺色背景。
不是逐一選擇零件,而是直接選擇整座工廠。
這就是抽象工廠的全部概念。
在 Swift 中一次替換相關物件
放到實際程式碼中會清楚許多。以下以 UI 主題為例。
先定義要建立之零件的規格(協定),以及產生這些零件的工廠規格。
protocol Button { func render() -> String }
protocol Label { func render() -> String }
// 工廠負責整組彼此搭配的零件
protocol ThemeFactory {
func makeButton() -> Button
func makeLabel() -> Label
}
接著分別建立淺色主題工廠和深色主題工廠。每座工廠只產生符合自身主題的零件。
struct LightFactory: ThemeFactory {
func makeButton() -> Button { LightButton() }
func makeLabel() -> Label { LightLabel() }
}
struct DarkFactory: ThemeFactory {
func makeButton() -> Button { DarkButton() }
func makeLabel() -> Label { DarkLabel() }
}
繪製畫面的程式只要取得一座工廠即可,不必在意它是哪一座工廠。
func buildScreen(with factory: ThemeFactory) {
let button = factory.makeButton()
let label = factory.makeLabel()
print(button.render(), label.render())
}
// 替換主題只要修改工廠的一行程式碼
buildScreen(with: DarkFactory())
將 LightFactory()替換成 DarkFactory()的瞬間,按鈕和標籤就會一起切換成深色。
不必再分別修改按鈕和標籤的顏色了。
它和工廠方法有什麼不同?
名稱相似,很容易混淆,這裡先說明兩者的差異。
| 分類 | 工廠方法 | 抽象工廠 |
|---|---|---|
| 建立對象 | 一種物件 | 多種相關物件(整組) |
| 重點 | 「要建立什麼?」 | 「將相容的物件綁在一起」 |
| 代表範例 | 建立一個按鈕 | 按鈕+標籤+背景一整套 |
簡單來說,工廠方法是建立單一零件的方法,而抽象工廠是把這些零件組成一整套的方法。
也可以把它理解成:抽象工廠中使用了多個工廠方法。
何時適合使用,何時應避免?
實際使用後,我發現適合的情境和反而過度設計的情境區分得很明顯。
適合的情況
- 當主題、平台、國家等明確以「整組」為單位變更時
- 當需要像 iOS 和 macOS 一樣整組替換 UI 元件時
- 當付款方式、資料庫驅動程式等需要成套替換時
這些情況會過度設計
- 只需要建立一兩種物件時
- 組合規則經常變動,導致整組本身不穩定時
明明只有一個物件,卻建立抽象工廠,反而會增加程式碼並降低可讀性。
在有明確理由要組成一整套時再使用它比較好。
兩個常見問題
Q. 之後想新增零件種類怎麼辦?
需要在協定中新增方法,並在所有工廠實作該方法。工廠很多時會相當費工,因此若專案中的零件種類會經常增加,最好事先考慮。
Q. SwiftUI 也會使用嗎?
當然可以,但 SwiftUI 已經提供 Environment 或 @Observable 這類內建注入方式,因此只處理主題時,通常那樣更簡潔。若是 UIKit 基礎架構,或純邏輯層需要替換整組物件,抽象工廠會更有價值。
抽象工廠終究是一種「用同一個把手綁住不能各自運作的事物」的模式。
試過只改一行主題就讓整個畫面完美搭配後,你就會立刻理解為什麼要使用這個模式。建議先從小型範例親手實作。

