软件设计

使用 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 为什么像地狱?

参数只有三四个时,其实没有什么大问题。

问题从参数数量增加时开始。

第一,容易弄错顺序。即使把 phone 放到 email 的位置,只要两者都是 String,编译器也不会报错。

第二,可选值的处理会变得杂乱。就连当前不用的值,也必须用 nil, nil, nil 填上。

第三,调用方变得很长,很难一眼看出正在创建什么对象。

参数越多,init 就越像一张“需要填满空白的试卷”;空白越多,错误也越多。

把 phone 和 profileURL 的位置放反,可能会让你排查一天以上。类型相同时,这类错误真的很难察觉。


什么是 Builder Pattern?

Builder Pattern 不会一次性创建复杂对象,而是逐个填入值,最后完成对象的创建。

它不是在初始化时传入所有值,而是选择并设置需要的值,最后通过类似 build() 的方法获取最终对象。

想象一下在餐厅点餐就容易理解了。不是一次喊出所有食材,而是逐项说:“面包要全麦,奶酪加量,不要酱汁。”

如果设置关键值的方法返回自身,就可以像连接点号一样进行链式调用。下面是最简单的 builder 形式。

final class UserBuilder {
    private var name = ""
    private var email: String?
    // 设置一个值并 self返回它,从而支持链式调用
    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(...) 一样继续调用。

链式调用实际是这样执行的
链式调用实际是这样执行的
加上一个 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 确实更方便。

问:创建 builder 后,代码不会变得更多吗?

没错。builder 类本身会增加代码。不过,如果这个对象要在多个地方创建,调用方变得整洁所带来的收益更大。

问:Swift 有默认参数,不能直接用它吗?

参数只有三四个时,只使用默认参数就够了。参数很多且组合多样时,Builder Pattern 的优势才会体现出来。


如果你正因 8 个参数的 init 而感到压力,不妨只在这个位置尝试 Builder Pattern。不必全部推倒重来,从最复杂的一个对象开始,负担会小很多。祝你编码愉快!

延伸阅读