軟體設計

用 Swift Builder Pattern 擺脫 8 個參數的初始化地獄

使用 Swift 製作 App 時,初始化程式碼不知不覺就會變成這個樣子。

閱讀 4 分鐘
用 Swift Builder Pattern 擺脫 8 個參數的初始化地獄 封面圖

使用 Swift 製作 App 時,初始化程式碼不知不覺就會變成這個樣子。

User(name:age:email:phone:address:isVerified:profileURL:createdAt:)

括號裡有 8 個參數。

看著呼叫端的程式碼,你得逐一用眼睛數,才能確認哪個值是 email、哪個是 phone。

這種情況在 side project 中也很常見,但用 Swift Builder Pattern 整理後就能俐落解決。

先說結論,將參數很多的初始化改成用 Builder Pattern「一行設定一個」,可讀性會大幅提升。不必記住順序,也不用勉強用 nil 填入未使用的值。

先整理這篇文章可以帶走的重點。

  1. 為什麼 8 個參數的 init 容易出錯
  2. Builder Pattern 如何解決這個問題
  3. Swift 中實際使用的程式碼形式
  4. 何時該使用、何時該避免這個模式

8 個參數的 init,為什麼像地獄?

參數只有 3、4 個時,其實不太會有問題。

問題會從參數數量增加後開始。

第一,容易搞錯順序。即使把 phone 放到 email 的位置,只要兩者都是 String,編譯器也抓不到。

第二,選用值會變得很凌亂。就連現在不用的值,也得用 nil, nil, nil 填上。

第三,呼叫端變得很長,很難一眼看出正在建立什麼物件。

參數越多,init 就越像一張「必須填滿空格的考卷」;空格越多,錯誤也會跟著增加。

把 phone 和 profileURL 的位置放反,可能會讓你花上一天以上除錯。型別相同時,這類錯誤真的很難察覺。


Builder Pattern 是什麼?

Builder Pattern 不會一次建立複雜物件,而是逐一填入值,最後再完成物件。

不要在初始化時傳入所有值,而是只選擇並設定需要的值,最後透過像 build() 這樣的方法取得完成的物件。

想像在餐廳點餐就很容易理解。不必一次喊出所有食材,而是逐項說:「麵包要全麥、起司加量、不要醬料。」

如果設定核心值的方法會回傳自身,就能像串接句點一樣進行 chaining。下面是最簡單的 Builder 形式。

final class UserBuilder {
    private var name = ""
    private var email: String?
    // 設定值並 self回傳自身,讓 chaining 成為可能
    func setName(_ v: String) -> Self { name = v; return self }
    func setEmail(_ v: String) -> Self { email = v; return self }
    func build() -> User { User(name: name, email: email) }
}

因為設定方法會回傳 Self,所以可以像 .setName(...).setEmail(...) 一樣串接。

Chaining 呼叫實際上會這樣流動
Chaining 呼叫實際上會這樣流動
加上一個 Builder,邊喝咖啡邊整理後,心情輕鬆多了
加上一個 Builder,邊喝咖啡邊整理後,心情輕鬆多了

Swift 中如何使用 Builder Pattern?

大家最想知道的,應該就是實際呼叫端會如何改變。

使用前面建立的 Builder 後,物件建立程式碼會變成這樣。

// 只設定需要的值,標示名稱並免去順序的顧慮
let user = UserBuilder()
    .setName("李錫宇")
    .setEmail("[email protected]")
    .build()
// 不用在未使用的值填入 nil

如你所見,不必再在意順序。方法名稱本身就是標籤,從結構上避免把 phone 放進 email 位置這類錯誤。

不用的值只要不呼叫對應方法即可。

在 Swift 中,也常用 struct 而非 class 建立 Builder,或傳入 closure,在同一個區塊內完成設定。請依專案風格選擇。

用帶有名稱標籤的方法串接後,再也不用擔心順序
用帶有名稱標籤的方法串接後,再也不用擔心順序

Builder Pattern 何時該用、何時該避免

只因為看起來不錯就到處加入,反而只會增加程式碼。

我把自己的判斷整理成表格(以 2026 年為止的個人專案經驗為基礎)。

情況 建議
5 個以上參數,選用值很多 Builder Pattern
有多個相同型別的參數 Builder Pattern
2~3 個參數,全部必要 一般 init
值單純且固定 一般 init

總結來說,參數少且全部必要時,沒有必要特地建立 Builder。

相反地,如果是混合許多選用值的大型物件,Builder 確實方便許多。

Q. 建立 Builder 後,程式碼不會變得更多嗎?

沒錯。Builder class 本身會增加程式碼。不過,如果這個物件會在多個地方建立,呼叫端變乾淨所帶來的好處更大。

Q. Swift 有預設參數,不能直接用那個嗎?

參數只有 3、4 個時,使用預設參數就足夠了。當參數很多、組合也多樣時,Builder 的優點才會真正發揮。


如果你正因為 8 個參數的 init 而感到壓力,不妨只在那個地方試用 Builder Pattern。不必全部重寫,從最複雜的一個物件開始,負擔會小很多。祝你今天也寫程式愉快!

延伸閱讀