Builder — az építész minta alapjai mobilfejlesztésben

Szerző: IT Sectr Megjelenés: 2026-02-17 Olvasási idő: 7 perc

Builder — egy létrehozási minta, amely lehetővé teszi összetett objektumok lépésenkénti létrehozását. Ellentétben a tíz paraméterrel rendelkező konstruktorral, a Builder az objektumot hívások láncán keresztül állítja össze, amelyek mindegyike egy mezőt állít be. A minta különösen hasznos sok opcionális paraméterrel rendelkező objektumokhoz: hálózati kliens konfigurációja, adatbázis beállítások, riasztások és navigáció építészei. Bővebben a Refactoring Guru: Builder oldalon.

Főbb pontok

  • Builder — objektumok lépésenkénti felépítése a folyamat és az eredmény szétválasztásával
  • Fluent interface — a set()/with() hívások lánca a kényelmes beállításhoz
  • Megváltoztathatatlanság — a Builder kész objektumot hoz létre, amely nem igényel settereket
  • Visszafelé kompatibilitás — új mezők adhatók a Builder-hez az ügyfelek megtörése nélkül
  • Kotlin DSL vs Builder — a Kotlin type-safe builders-t kínál alternatívaként

Mi a Builder: az építész minta lényege?

Builder (építész) — egy GoF létrehozási minta, amely elválasztja az összetett objektum felépítését annak reprezentációjától. Ugyanaz az építési folyamat különböző reprezentációkat hozhat létre. A Builder akkor hasznos, ha egy objektumnak sok opcionális paramétere van, és a tíz mezővel rendelkező konstruktor olvashatatlan és rugalmatlan. A minta megoldja a Telescoping Constructor problémáját is — egy anti-mintát, ahol a konstruktor túlterheléseinek száma exponenciálisan nő.

Builder struktúrája magában foglal egy belső statikus Builder osztályt, amelynek mezői a fő osztály mezőit másolják. Minden set-metódus visszaadja a Builder-t (this) a fluent chaining-hez. A végső build() metódus létrehozza a cél objektumot, átadva a mezőértékeket a privát konstruktornak. A fő osztálynak privát konstruktora van, amely elfogadja a Builder-t. Ügyfél: Object.builder().setField1(val1).setField2(val2).build().

Mikor használjuk a Builder-t — 5+ mezővel rendelkező objektumok, amelyekből csak 2-3 kötelező. Konfigurációs objektumok (RequestConfig, DatabaseConfig). Összetett érvényesítési logikával rendelkező objektumok létrehozáskor. Objektumok, amelyeknek létrehozás után megváltoztathatatlannak (immutable) kell lenniük. Androidban a Builder aktívan használatos az SDK-ban: AlertDialog.Builder, Retrofit.Builder, OkHttpClient.Builder, NotificationCompat.Builder.

Builder Kotlinban: klasszikus és DSL megvalósítás

Kotlin Builder két megközelítéssel rendelkezik: klasszikus Java-style Builder (beágyazott osztályon keresztül) és Kotlin-style DSL builder (lambda fogadóval). A Java-style Builder előnyösebb az Android kompatibilitás és a Java kóddal való használat esetén. DSL builder — idiomatikus Kotlin mód: a függvény lambdát fogad, amelyen belül a this a Builder kontextus, ahol a mezők közvetlenül hozzárendelhetők.

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

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

Kotlin DSL builder — alternatíva beágyazott osztály nélkül. A builder-függvény lambdát fogad az építész objektum kontextusában. Ez idiomatikus Kotlinhoz, és nem igényel write-mezőket. A DSL builders aktívan használatosak a Ktor Client, kotlinx.serialization, Compose (Modifier) rendszerekben. A DSL builder nem kompatibilis Java-val, és nem alkalmas Java API-val rendelkező könyvtárakhoz.

Builder Swiftben: result builders és láncok

Swift Builder — a Swift nem rendelkezik beépített Builder mintával, de a fluent interface könnyen megvalósítható Self-et visszaadó metódusokon keresztül. Minden metódus beállít egy tulajdonságot és visszaadja a self-et. Kotlinnal ellentétben a Swift nem igényel külön Builder osztályt — maga az objektum visszaadható, ha az összeszerelési szakaszban mutable. Immutable objektumokhoz beágyazott Builder osztály használatos, hasonlóan a Kotlinhoz.

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 — a Swift 5.4 bevezette a @resultBuilder-t — egy nyelvi mechanizmust struktúrák deklaratív felépítéséhez. A SwiftUI, AttributedString, SceneBuilder result builders-t használ. Ez egy alternatíva a klasszikus Builder helyett: a set-metódusok lánca helyett a result builder egy kódblokkot használ elemekkel, amelyeket a fordító egy tömbben vagy fában gyűjt össze. A @ViewBuilder a SwiftUI-ban — a leghíresebb példa: a body-n belül írható if, switch, ForEach, és a fordító View-t épít a feltételekből.

Builder vs Telescoping Constructor: megközelítések összehasonlítása

Telescoping Constructor — egy anti-minta, ahol egy osztálynak több túlterhelt konstruktora van különböző paraméterkészletekkel. Például három konstruktor: HttpConfig(url), HttpConfig(url, timeout), HttpConfig(url, timeout, retries). A paraméterek növekedésével a konstruktorok száma exponenciálisan nő — n opcionális mezőhöz n! kombináció szükséges. A Builder megoldja ezt a problémát azáltal, hogy csak a szükséges mezők beállítását teszi lehetővé.

JellemzőTelescoping ConstructorBuilderKotlin named args
Kód mennyiségeExponenciális növekedésLineáris növekedésMinimális
OlvashatóságAlacsony (melyik paraméter?)Magas (metódus + név)Magas (név = érték)
MegváltoztathatatlanságImmutableImmutableImmutable
Java kompatibilitásTeljesTeljesNem (csak Kotlin)
ÉrvényesítésMinden konstruktorbanbuild()-ben — egyszerinit()-ben

Kotlin named arguments + default values — elegáns alternatíva a Builder helyett tiszta Kotlin projektekben. A konstruktor paramétereinek alapértelmezett értékei vannak, az ügyfél csak a szükségeseket adja át: HttpConfig(baseUrl = url, timeout = 15_000). Hátrány — a kötelező mezők érvényesítésének lehetetlensége fordítási szakaszban. A Builder kötelező mezőket ad a Builder konstruktoron keresztül (baseUrl kötelező). Java könyvtárakhoz a Builder de facto szabvány marad.

Builder az Android SDK-ban: AlertDialog, Retrofit, OkHttp

Builder az Android SDK-ban — az egyik leggyakoribb minta a szabványos könyvtárban. 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().

Miért használ a Google Builder-t — visszafelé kompatibilitás. Egy új metódus hozzáadása a Builder-ben nem töri meg a meglévő kódot. Ha a Google 20 paraméteres konstruktort használt volna, minden új mezőhöz új túlterhelésre lett volna szükség. A Builder lehetővé teszi set-metódusok hozzáadását évekig breaking changes nélkül. Például a NotificationCompat.Builder hozzáadta a setBubbleMetadata() metódust Android 11-ben anélkül, hogy befolyásolta volna a meglévő kódot.

Builder Kotlin könyvtárakban — Ktor (HttpClientBuilder), Coil (ImageRequest.Builder), Room (Room.databaseBuilder()), Navigation (NavOptionsBuilder). Kotlin projektekben a Builder gyakran kombinálódik DSL-lel: Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build(). A minta továbbra is releváns a nyilvános API-khoz, ahol fontos a visszafelé kompatibilitás és a Java interoperabilitás.

Gyakran ismételt kérdések

Mikor felesleges a Builder?

A Builder felesleges az 1-3 mezővel rendelkező objektumokhoz — a szokásos konstruktor vagy data class érthetőbb. Szintén felesleges a Java interoperabilitás nélküli Kotlin projektekben, ahol a named arguments + default values egyszerűbben oldják meg ugyanazt a feladatot. A Builder 5+ mező, összetett érvényesítés vagy olyan Java API esetén indokolt, ahol a named arguments nem elérhetők.

Miben különbözik a Builder a Factory-tól?

A Builder egy összetett objektumot hoz létre lépésenként (mezők beállítása), a Factory egy objektumot teljes egészében hoz létre típus vagy paraméterek alapján. A Builder a «hogyan állítsuk össze?» kérdésre válaszol, a Factory — «mit hozzunk létre?». A Builder gyakran kombinálódik a Factory-val: a Factory kiválasztja a típust, a Builder beállítja a mezőket.

Szükséges-e a Builder a SwiftUI-ban?

A SwiftUI-ban a Builder szerepét a result builders (@ViewBuilder, @SceneBuilder) és a View módosítók (.font(), .padding()) töltik be. Klasszikus Builder nem szükséges, mivel a SwiftUI deklaratív megközelítést és fluent modifiers-t használ. UIKit komponensekhez a Builder hasznos: UIAlertController, URLRequest, NSAttributedString.

Hogyan tegyük a Builder-t thread-safe-té?

A Builder általában nem igényel szálbiztonságot, mivel egy szálban használatos az objektum összeszereléséhez. Ha a Builder többszálas környezetben használatos (ritka eset), szinkronizáljon minden set-metódust és build()-et. Alternatíva — Immutable Builder: minden set-metódus egy új Builder példányt ad vissza a módosított mezővel.

Miért használ a Retrofit Builder-t, nem DI-t?

A Retrofit.Builder a könyvtár nyilvános API-ja, amelynek DI konténer nélkül kell működnie. A Builder konfigurációs rugalmasságot biztosít (baseUrl, konverterek, interceptors, egyéni call adapterek) anélkül, hogy függne Dagger-től vagy más DI-től. Az alkalmazáson belül a DI létrehozhatja a Retrofit-ot egyszer a Builder-en keresztül, de maga a Builder a Retrofit nyilvános API-jának része marad.

Összegzés

  • Builder — objektumok lépésenkénti felépítése fluent interface-szel
  • Kotlin Builder — klasszikus (beágyazott osztály) és DSL (lambda fogadóval)
  • Swift Builder — beágyazott osztály vagy @resultBuilder deklaratív kódhoz
  • Megváltoztathatatlanság — a Builder immutable objektumokat hoz létre privát konstruktoron keresztül
  • Android SDK — AlertDialog, Retrofit, OkHttp, NotificationCompat — iparági szabvány
  • Visszafelé kompatibilitás — mezők hozzáadása a Builder-ben nem töri meg a meglévő kódot
  • Kotlin alternatíva — a named arguments + default values egyszerűbb tiszta Kotlin projektekhez

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is