Builder — основы паттерна строитель в мобильной разработке

Автор: IT Sectr Опубликовано: 2026-02-17 Время чтения: 7 мин

Builder — порождающий паттерн, позволяющий создавать сложные объекты пошагово. В отличие от конструктора с десятком параметров, Builder собирает объект через цепочку вызовов, каждый из которых настраивает одно поле. Паттерн особенно полезен для объектов с множеством опциональных параметров: конфигурация сетевого клиента, настройки базы данных, билдеры алертов и навигации. Подробнее — на Refactoring Guru: Builder.

Главное

  • Builder — пошаговое конструирование объектов с разделением процесса и результата
  • Fluent interface — цепочка вызовов set()/with() для удобной настройки
  • Неизменяемость — Builder создаёт готовый объект, который не требует сеттеров
  • Обратная совместимость — новые поля добавляются в Builder без ломки клиентов
  • Kotlin DSL vs Builder — Kotlin предлагает type-safe builders как альтернативу

Что такое Builder: суть паттерна строитель?

Builder (строитель) — порождающий паттерн GoF, который отделяет конструирование сложного объекта от его представления. Один и тот же процесс построения может создавать разные представления. Builder полезен, когда объект имеет много опциональных параметров, а конструктор с десятью полями нечитаем и негибок. Паттерн также решает проблему Telescoping Constructor — антипаттерна, где количество перегрузок конструктора растёт экспоненциально.

Структура Builder включает внутренний статический класс Builder с полями, копирующими поля основного класса. Каждый set-метод возвращает Builder (this) для fluent chaining. Финальный метод 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.

Builder в Kotlin: классическая и DSL-реализация

Kotlin Builder имеет два подхода: классический Java-style Builder (через вложенный класс) и Kotlin-style DSL builder (через лямбду с ресивером). Java-style Builder предпочтителен для Android-совместимости и при использовании с Java-кодом. DSL builder — идиоматичный Kotlin-способ: функция принимает лямбду, внутри которой 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 builder — альтернатива без вложенного класса. Функция-билдер принимает лямбду в контексте объекта-строителя. Это идиоматично для Kotlin и не требует write-полей. DSL builders активно используются в Ktor Client, kotlinx.serialization, Compose (Modifier). DSL builder несовместим с Java и не подходит для библиотек с Java API.

Builder в Swift: result builders и цепочки

Swift Builder — Swift не имеет встроенного паттерна Builder, но fluent interface легко реализуется через методы, возвращающие Self. Каждый метод настраивает свойство и возвращает self. В отличие от Kotlin, Swift не требует отдельного Builder-класса — можно возвращать сам объект, если он mutable на этапе сборки. Для immutable объектов используется вложенный Builder-класс по аналогии с Kotlin.

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: вместо цепочки set-методов result builder использует блок кода с элементами, которые компилятор собирает в массив или дерево. @ViewBuilder в SwiftUI — самый известный пример: внутри body можно писать if, switch, ForEach, и компилятор строит View из условий.

Builder vs Telescoping Constructor: сравнение подходов

Telescoping Constructor — антипаттерн, при котором класс имеет множество перегруженных конструкторов с разным набором параметров. Например, три конструктора: HttpConfig(url), HttpConfig(url, timeout), HttpConfig(url, timeout, retries). С ростом параметров количество конструкторов растёт экспоненциально — для n optional полей нужно n! комбинаций. Builder решает эту проблему, позволяя задавать только нужные поля.

ХарактеристикаTelescoping ConstructorBuilderKotlin named args
Количество кодаЭкспоненциальный ростЛинейный ростМинимальное
ЧитаемостьНизкая (какой параметр какой?)Высокая (метод + имя)Высокая (имя = значение)
НеизменяемостьImmutableImmutableImmutable
Java-совместимостьПолнаяПолнаяНет (только Kotlin)
ВалидацияВ каждом конструктореВ build() — один разВ init()

Kotlin named arguments + default values — элегантная альтернатива Builder в чистых Kotlin-проектах. Параметры конструктора имеют значения по умолчанию, клиент передаёт только нужные: HttpConfig(baseUrl = url, timeout = 15_000). Недостаток — невозможность валидации обязательных полей на этапе компиляции. Builder даёт обязательные поля через конструктор Builder (baseUrl обязателен). Для Java-библиотек Builder остаётся стандартом де-факто.

Builder в Android SDK: AlertDialog, Retrofit, OkHttp

Builder в Android SDK — один из самых распространённых паттернов в стандартной библиотеке. 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-методы годами без breaking changes. Например, NotificationCompat.Builder добавил setBubbleMetadata() в Android 11, не затронув существующий код.

Builder в Kotlin-библиотеках — Ktor (HttpClientBuilder), Coil (ImageRequest.Builder), Room (Room.databaseBuilder()), Navigation (NavOptionsBuilder). В Kotlin-проектах Builder часто комбинируется с DSL: Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build(). Паттерн остаётся актуальным для публичных API, где важна обратная совместимость и Java-интероп.

Часто задаваемые вопросы

Когда Builder избыточен?

Builder избыточен для объектов с 1-3 полями — обычный конструктор или data class понятнее. Также избыточен в Kotlin-проектах без Java-интеропа, где named arguments + default values решают ту же задачу проще. Builder оправдан для 5+ полей, сложной валидации или Java API, где named arguments недоступны.

Чем Builder отличается от Factory?

Builder создаёт один сложный объект пошагово (настройка полей), Factory создаёт объект целиком по типу или параметрам. Builder отвечает на вопрос «как собрать?», Factory — «что создать?». Builder часто объединяется с Factory: Factory выбирает тип, Builder настраивает поля.

Нужен ли Builder в SwiftUI?

В SwiftUI роль Builder выполняют result builders (@ViewBuilder, @SceneBuilder) и модификаторы View (.font(), .padding()). Классический Builder не требуется, так как SwiftUI использует декларативный подход и fluent modifiers. Для UIKit-компонентов Builder полезен: UIAlertController, URLRequest, NSAttributedString.

Как сделать Builder потокобезопасным?

Builder обычно не требует потокобезопасности, так как используется в одном потоке для сборки объекта. Если Builder используется в многопоточной среде (редкий кейс), синхронизируйте каждый set-метод и build(). Альтернатива — Immutable Builder: каждый set-метод возвращает новый экземпляр Builder с изменённым полем.

Почему Retrofit использует Builder, а не DI?

Retrofit.Builder — публичный API библиотеки, который должен работать без DI-контейнера. Builder даёт гибкость настройки (baseUrl, конвертеры, interceptors, кастомные call adapters) без зависимостей от Dagger или других DI. Внутри приложения DI может создать Retrofit один раз через Builder, но сам Builder остаётся частью публичного API Retrofit.

Итоги

  • Builder — пошаговое конструирование объектов с fluent interface
  • Kotlin Builder — классический (вложенный класс) и DSL (лямбда с ресивером)
  • Swift Builder — вложенный класс или @resultBuilder для декларативного кода
  • Неизменяемость — Builder создаёт immutable объекты через приватный конструктор
  • Android SDK — AlertDialog, Retrofit, OkHttp, NotificationCompat — стандарт индустрии
  • Обратная совместимость — добавление полей в Builder не ломает существующий код
  • Альтернатива Kotlin — named arguments + default values проще для чистых Kotlin проектов

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также