Builder — 移动开发中构建者模式的基础

作者: IT Sectr 发布日期: 2026-02-17 阅读时间: 7 分钟

Builder — 一种创建型模式,允许逐步创建复杂对象。与具有十个参数的构造函数不同,Builder通过链式调用组装对象,每个调用设置一个字段。该模式特别适用于具有多个可选参数的对象:网络客户端配置、数据库设置、警报和导航构建器。更多信息请访问Refactoring Guru: Builder

要点

  • Builder — 将过程与结果分离的逐步对象构建
  • Fluent interface — 用于方便配置的set()/with()链式调用
  • 不变性 — Builder创建不需要setter的现成对象
  • 向后兼容 — 新字段在不破坏客户端的情况下添加到Builder中
  • Kotlin DSL vs Builder — Kotlin提供类型安全构建器作为替代方案

什么是Builder:构建者模式的本质?

Builder(构建者)— 一种GoF创建型模式,它将复杂对象的构建与其表示分离。相同的构建过程可以创建不同的表示。当一个对象有许多可选参数,而具有十个字段的构造函数难以阅读且不灵活时,Builder非常有用。该模式还解决了Telescoping Constructor(望远镜构造函数)问题 — 一种反模式,其中构造函数重载的数量呈指数增长。

Builder结构包括一个内部静态Builder类,其字段复制主类的字段。每个set方法返回Builder(this)以实现流畅链式调用。最终的build()方法创建目标对象,将字段值传递给私有构造函数。主类有一个接受Builder的私有构造函数。客户端:Object.builder().setField1(val1).setField2(val2).build()。

何时使用Builder — 具有5+字段的对象,其中只有2-3个是必填的。配置对象(RequestConfig, DatabaseConfig)。创建时具有复杂验证逻辑的对象。创建后应保持不变(immutable)的对象。在Android中,Builder在SDK中被广泛使用:AlertDialog.Builder、Retrofit.Builder、OkHttpClient.Builder、NotificationCompat.Builder。

Kotlin中的Builder:经典和DSL实现

Kotlin Builder有两种方法:经典的Java风格Builder(通过嵌套类)和Kotlin风格DSL构建器(通过带接收者的lambda)。Java风格Builder在Android兼容性和与Java代码一起使用时更受青睐。DSL构建器 — 符合Kotlin习惯用法的方式:函数接受lambda,其中this是Builder上下文,可以直接分配字段。

kotlin
// 经典Builder
data class HttpConfig private constructor(
    val baseUrl: String,
    val timeout: Long = 30_000,
    val retries: Int = 3,
    val headers: Map<String, String> = emptyMap()
) {
    class Builder {
        private var baseUrl: String = ""
        private var timeout: Long = 30_000
        private var retries: Int = 3
        private var headers: MutableMap<String, String> = mutableMapOf()

        fun baseUrl(url: String) = apply { this.baseUrl = url }
        fun timeout(ms: Long) = apply { this.timeout = ms }
        fun retries(n: Int) = apply { this.retries = n }
        fun header(key: String, value: String) = apply { headers[key] = value }

        fun build(): HttpConfig {
            require(baseUrl.isNotBlank()) { "baseUrl is required" }
            return HttpConfig(baseUrl, timeout, retries, headers)
        }
    }
}

// 使用
val config = HttpConfig.Builder()
    .baseUrl("https://api.example.com")
    .timeout(15_000)
    .header("Authorization", "Bearer token")
    .build()

Kotlin DSL构建器 — 无需嵌套类的替代方案。构建器函数在构建者对象的上下文中接受lambda。这对Kotlin来说符合习惯用法,并且不需要write字段。DSL构建器在Ktor Client、kotlinx.serialization、Compose(Modifier)中被广泛使用。DSL构建器不兼容Java,不适合具有Java API的库。

Swift中的Builder:result builders和链式调用

Swift Builder — Swift没有内置的Builder模式,但可以通过返回Self的方法轻松实现流畅接口。每个方法设置一个属性并返回self。与Kotlin不同,Swift不需要单独的Builder类 — 如果对象在组装阶段是可变的,则可以返回对象本身。对于不可变对象,使用类似于Kotlin的嵌套Builder类。

swift
struct NetworkRequest {
    let url: String
    let method: HTTPMethod
    let headers: [String: String]
    let body: Data?
    let timeout: TimeInterval

    final class Builder {
        private var url: String = ""
        private var method: HTTPMethod = .get
        private var headers: [String: String] = [:]
        private var body: Data? = nil
        private var timeout: TimeInterval = 30

        func withURL(_: String) -> Self { /* self */ }
        func withMethod(_: HTTPMethod) -> Self { /* self */ }
        func withHeader(key: String, value: String) -> Self { /* self */ }
        func withBody(_: Data) -> Self { /* self */ }
        func withTimeout(_: TimeInterval) -> Self { /* self */ }

        func build() throws -> NetworkRequest {
            guard !url.isEmpty else { throw BuilderError.missingURL }
            return NetworkRequest(
                url: url, method: method, headers: headers,
                body: body, timeout: timeout
            )
        }
    }
}

Result Builders — Swift 5.4引入了@resultBuilder — 一种用于声明式构建结构的语言机制。SwiftUI、AttributedString、SceneBuilder使用result builders。这是经典Builder的替代方案:result builder不使用set方法链,而是使用一个代码块,其中包含编译器收集到数组或树中的元素。SwiftUI中的@ViewBuilder是最著名的例子:在body内部可以写if、switch、ForEach,编译器从条件中构建View。

Builder vs Telescoping Constructor:方法比较

Telescoping Constructor — 一种反模式,其中一个类具有多个重载的构造函数,具有不同的参数集。例如,三个构造函数:HttpConfig(url)、HttpConfig(url, timeout)、HttpConfig(url, timeout, retries)。随着参数的增加,构造函数的数量呈指数增长 — 对于n个可选字段,需要n!种组合。Builder通过允许仅设置必要字段来解决此问题。

特性Telescoping ConstructorBuilderKotlin命名参数
代码量指数增长线性增长最小
可读性低(哪个参数?)高(方法+名称)高(名称=值)
不变性不可变不可变不可变
Java兼容性完全完全否(仅Kotlin)
验证在每个构造函数中在build()中 — 一次在init()中

Kotlin命名参数 + 默认值 — 在纯Kotlin项目中优雅的Builder替代方案。构造函数参数有默认值,客户端只传递需要的参数:HttpConfig(baseUrl = url, timeout = 15_000)。缺点 — 无法在编译阶段验证必填字段。Builder通过Builder构造函数提供必填字段(baseUrl是必填的)。对于Java库,Builder仍然是事实上的标准。

Android SDK中的Builder:AlertDialog、Retrofit、OkHttp

Android SDK中的Builder — 标准库中最常见的模式之一。AlertDialog.Builder:new AlertDialog.Builder(context).setTitle().setMessage().setPositiveButton().create()。Retrofit.Builder:new Retrofit.Builder().baseUrl().addConverterFactory().build()。OkHttpClient.Builder:new OkHttpClient.Builder().connectTimeout().addInterceptor().build()。NotificationCompat.Builder:setContentTitle().setContentText().setSmallIcon().build()。

为什么Google使用Builder — 向后兼容。在Builder中添加新方法不会破坏现有代码。如果Google使用具有20个参数的构造函数,每个新字段都需要新的重载。Builder允许多年添加set方法而不会产生破坏性变更。例如,NotificationCompat.Builder在Android 11中添加了setBubbleMetadata(),而不影响现有代码。

Kotlin库中的Builder — Ktor(HttpClientBuilder)、Coil(ImageRequest.Builder)、Room(Room.databaseBuilder())、Navigation(NavOptionsBuilder)。在Kotlin项目中,Builder通常与DSL结合使用:Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build()。对于向后兼容和Java互操作性重要的公共API,该模式仍然具有相关性。

常见问题

何时Builder多余?

对于具有1-3个字段的对象,Builder是多余的 — 普通构造函数或data class更容易理解。在没有Java互操作性的Kotlin项目中也是多余的,因为命名参数+默认值可以更简单地解决相同的任务。Builder适用于5+字段、复杂验证或命名参数不可用的Java API。

Builder与Factory有何不同?

Builder逐步创建一个复杂对象(设置字段),Factory根据类型或参数创建完整的对象。Builder回答「如何组装?」的问题,Factory回答「创建什么?」。Builder经常与Factory结合使用:Factory选择类型,Builder设置字段。

SwiftUI中需要Builder吗?

在SwiftUI中,Builder的角色由result builders(@ViewBuilder、@SceneBuilder)和View修饰符(.font()、.padding())承担。不需要经典的Builder,因为SwiftUI使用声明式方法和流畅修饰符。对于UIKit组件,Builder很有用:UIAlertController、URLRequest、NSAttributedString。

如何使Builder线程安全?

Builder通常不需要线程安全,因为它在一个线程中用于组装对象。如果在多线程环境中使用Builder(罕见情况),请同步每个set方法和build()。替代方案 — 不可变Builder:每个set方法返回一个具有修改字段的新Builder实例。

为什么Retrofit使用Builder而不是DI?

Retrofit.Builder是库的公共API,必须无需DI容器即可使用。Builder提供配置灵活性(baseUrl、转换器、拦截器、自定义调用适配器),而不依赖于Dagger或其他DI。在应用程序内部,DI可以通过Builder创建一次Retrofit,但Builder本身仍然是Retrofit公共API的一部分。

总结

  • Builder — 具有流畅接口的逐步对象构建
  • Kotlin Builder — 经典(嵌套类)和DSL(带接收者的lambda)
  • Swift Builder — 嵌套类或用于声明式代码的@resultBuilder
  • 不变性 — Builder通过私有构造函数创建不可变对象
  • Android SDK — AlertDialog、Retrofit、OkHttp、NotificationCompat — 行业标准
  • 向后兼容 — 在Builder中添加字段不会破坏现有代码
  • Kotlin替代方案 — 命名参数+默认值对纯Kotlin项目更简单

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读