Builder — bazele modelului constructor în dezvoltarea mobilă

Autor: IT Sectr Publicat: 2026-02-17 Timp de citire: 7 min

Builder — un model de creare care permite construirea obiectelor complexe pas cu pas. Spre deosebire de un constructor cu zece parametri, Builder asamblează obiectul printr-un lanț de apeluri, fiecare dintre ele setând un câmp. Modelul este util în special pentru obiectele cu mulți parametri opționali: configurarea clientului de rețea, setările bazei de date, constructorii de alerte și navigare. Mai multe pe Refactoring Guru: Builder.

Principalele

  • Builder — construirea pas cu pas a obiectelor cu separarea procesului și rezultatului
  • Fluent interface — lanț de apeluri set()/with() pentru configurare ușoară
  • Imutabilitate — Builder creează un obiect gata care nu necesită setteri
  • Compatibilitate inversă — câmpuri noi se adaugă în Builder fără a afecta clienții
  • Kotlin DSL vs Builder — Kotlin oferă type-safe builders ca alternativă

Ce este Builder: esența modelului constructor?

Builder (constructor) — un model de creare GoF care separă construirea unui obiect complex de reprezentarea sa. Același proces de construire poate crea reprezentări diferite. Builder este util atunci când un obiect are mulți parametri opționali, iar un constructor cu zece câmpuri este ilizibil și inflexibil. Modelul rezolvă și problema Telescoping Constructor — un anti-model în care numărul de supraîncărcări ale constructorului crește exponențial.

Structura Builder include o clasă statică internă Builder cu câmpuri care copiază câmpurile clasei principale. Fiecare metodă set returnează Builder (this) pentru fluent chaining. Metoda finală build() creează obiectul țintă, transmițând valorile câmpurilor către constructorul privat. Clasa principală are un constructor privat care primește Builder. Client: Object.builder().setField1(val1).setField2(val2).build().

Când să folosim Builder — obiecte cu 5+ câmpuri, dintre care doar 2-3 obligatorii. Obiecte de configurare (RequestConfig, DatabaseConfig). Obiecte cu logică complexă de validare la creare. Obiecte care trebuie să fie imutabile (immutable) după creare. În Android, Builder este utilizat activ în SDK: AlertDialog.Builder, Retrofit.Builder, OkHttpClient.Builder, NotificationCompat.Builder.

Builder în Kotlin: implementare clasică și DSL

Kotlin Builder are două abordări: Builder clasic în stil Java (printr-o clasă imbricată) și DSL builder în stil Kotlin (printr-o lambda cu receiver). Builder în stil Java este preferat pentru compatibilitatea cu Android și la utilizarea cu cod Java. DSL builder — modul idiomatic Kotlin: funcția primește o lambda, în interiorul căreia this este contextul Builder, unde se pot atribui direct câmpuri.

kotlin
// Builder clasic
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)
        }
    }
}

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

Kotlin DSL builder — alternativă fără clasă imbricată. Funcția-builder primește o lambda în contextul obiectului-constructor. Este idiomatic pentru Kotlin și nu necesită câmpuri write. DSL builders sunt utilizate activ în Ktor Client, kotlinx.serialization, Compose (Modifier). DSL builder este incompatibil cu Java și nu este potrivit pentru bibliotecile cu API Java.

Builder în Swift: result builders și lanțuri

Swift Builder — Swift nu are un model Builder încorporat, dar fluent interface se implementează ușor prin metode care returnează Self. Fiecare metodă setează o proprietate și returnează self. Spre deosebire de Kotlin, Swift nu necesită o clasă Builder separată — se poate returna obiectul însuși dacă este mutable în faza de asamblare. Pentru obiecte immutabile se folosește o clasă Builder imbricată similar cu 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 a introdus @resultBuilder — un mecanism lingvistic pentru construirea declarativă a structurilor. SwiftUI, AttributedString, SceneBuilder folosesc result builders. Este o alternativă la Builder clasic: în locul unui lanț de metode set, result builder folosește un bloc de cod cu elemente pe care compilatorul le colectează într-un tablou sau arbore. @ViewBuilder în SwiftUI — cel mai cunoscut exemplu: în interiorul body se pot scrie if, switch, ForEach, iar compilatorul construiește View din condiții.

Builder vs Telescoping Constructor: compararea abordărilor

Telescoping Constructor — un anti-model în care o clasă are multiple constructori supraîncărcați cu seturi diferite de parametri. De exemplu, trei constructori: HttpConfig(url), HttpConfig(url, timeout), HttpConfig(url, timeout, retries). Odată cu creșterea parametrilor, numărul de constructori crește exponențial — pentru n câmpuri opționale sunt necesare n! combinații. Builder rezolvă această problemă permițând setarea doar a câmpurilor necesare.

CaracteristicăTelescoping ConstructorBuilderKotlin named args
Cantitatea de codCreștere exponențialăCreștere liniarăMinimă
LizibilitateScăzută (care parametru?)Ridicată (metodă + nume)Ridicată (nume = valoare)
ImutabilitateImmutableImmutableImmutable
Compatibilitate JavaCompletăCompletăNu (doar Kotlin)
ValidareÎn fiecare constructorÎn build() — o singură datăÎn init()

Kotlin named arguments + default values — o alternativă elegantă la Builder în proiectele pure Kotlin. Parametrii constructorului au valori implicite, clientul transmite doar pe cei necesari: HttpConfig(baseUrl = url, timeout = 15_000). Dezavantaj — imposibilitatea validării câmpurilor obligatorii la etapa de compilare. Builder oferă câmpuri obligatorii prin constructorul Builder (baseUrl este obligatoriu). Pentru bibliotecile Java, Builder rămâne standardul de facto.

Builder în Android SDK: AlertDialog, Retrofit, OkHttp

Builder în Android SDK — unul dintre cele mai răspândite modele în biblioteca standard. 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().

De ce Google folosește Builder — compatibilitate inversă. Adăugarea unei noi metode în Builder nu distruge codul existent. Dacă Google ar fi folosit un constructor cu 20 de parametri, fiecare câmp nou ar necesita o nouă supraîncărcare. Builder permite adăugarea de metode set ani de zile fără breaking changes. De exemplu, NotificationCompat.Builder a adăugat setBubbleMetadata() în Android 11, fără a afecta codul existent.

Builder în bibliotecile Kotlin — Ktor (HttpClientBuilder), Coil (ImageRequest.Builder), Room (Room.databaseBuilder()), Navigation (NavOptionsBuilder). În proiectele Kotlin, Builder este adesea combinat cu DSL: Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build(). Modelul rămâne relevant pentru API-urile publice unde sunt importante compatibilitatea inversă și interoperabilitatea cu Java.

Întrebări frecvente

Când este Builder redundant?

Builder este redundant pentru obiecte cu 1-3 câmpuri — un constructor obișnuit sau data class sunt mai clare. De asemenea, este redundant în proiectele Kotlin fără interoperabilitate Java, unde named arguments + default values rezolvă aceeași sarcină mai simplu. Builder este justificat pentru 5+ câmpuri, validare complexă sau API Java unde named arguments nu sunt disponibile.

Cu ce se deosebește Builder de Factory?

Builder creează un obiect complex pas cu pas (setarea câmpurilor), Factory creează un obiect integral după tip sau parametri. Builder răspunde la întrebarea «cum să asamblăm?», Factory — «ce să creăm?». Builder este adesea combinat cu Factory: Factory alege tipul, Builder setează câmpurile.

Este necesar Builder în SwiftUI?

În SwiftUI, rolul Builder este îndeplinit de result builders (@ViewBuilder, @SceneBuilder) și modificatorii View (.font(), .padding()). Builder clasic nu este necesar, deoarece SwiftUI folosește o abordare declarativă și fluent modifiers. Pentru componentele UIKit, Builder este util: UIAlertController, URLRequest, NSAttributedString.

Cum se face Builder thread-safe?

Builder de obicei nu necesită siguranță la fire, deoarece este utilizat într-un singur fir pentru asamblarea obiectului. Dacă Builder este utilizat într-un mediu multi-thread (caz rar), sincronizați fiecare metodă set și build(). Alternativă — Immutable Builder: fiecare metodă set returnează o nouă instanță Builder cu câmpul modificat.

De ce Retrofit folosește Builder, nu DI?

Retrofit.Builder este API-ul public al bibliotecii care trebuie să funcționeze fără container DI. Builder oferă flexibilitate de configurare (baseUrl, convertoare, interceptori, adaptoare de apel personalizate) fără dependențe de Dagger sau alte DI. În interiorul aplicației, DI poate crea Retrofit o dată prin Builder, dar Builder însuși rămâne parte a API-ului public Retrofit.

Concluzii

  • Builder — construirea pas cu pas a obiectelor cu fluent interface
  • Kotlin Builder — clasic (clasă imbricată) și DSL (lambdă cu receiver)
  • Swift Builder — clasă imbricată sau @resultBuilder pentru cod declarativ
  • Imutabilitate — Builder creează obiecte immutable prin constructor privat
  • Android SDK — AlertDialog, Retrofit, OkHttp, NotificationCompat — standardul industriei
  • Compatibilitate inversă — adăugarea câmpurilor în Builder nu distruge codul existent
  • Alternativa Kotlin — named arguments + default values mai simplu pentru proiectele pure Kotlin

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și