Builder — grunderna i byggarmönstret inom mobilutveckling

Författare: IT Sectr Publicerad: 2026-02-17 Lästid: 7 min

Builder — ett skapandemönster som gör det möjligt att skapa komplexa objekt steg för steg. Till skillnad från en konstruktor med tio parametrar, bygger Builder ihop objektet genom en kedja av anrop, var och en sätter ett fält. Mönstret är särskilt användbart för objekt med många valfria parametrar: konfiguration av nätverksklient, databasinställningar, byggare för alertar och navigering. Mer på Refactoring Guru: Builder.

Huvudpunkter

  • Builder — stegvis objektkonstruktion med separation av process och resultat
  • Fluent interface — kedja av set()/with()-anrop för enkel konfiguration
  • Oföränderlighet — Builder skapar ett färdigt objekt som inte kräver setter
  • Bakåtkompatibilitet — nya fält läggs till i Builder utan att bryta klienter
  • Kotlin DSL vs Builder — Kotlin erbjuder type-safe builders som alternativ

Vad är Builder: essensen av byggarmönstret?

Builder (byggare) — ett GoF-skapandemönster som separerar konstruktionen av ett komplext objekt från dess representation. Samma byggprocess kan skapa olika representationer. Builder är användbart när ett objekt har många valfria parametrar och en konstruktor med tio fält är oläslig och inflexibel. Mönstret löser också problemet med Telescoping Constructor — ett anti-mönster där antalet överlagringar av konstruktorn växer exponentiellt.

Builder-struktur inkluderar en inre statisk Builder-klass med fält som kopierar huvudklassens fält. Varje set-metod returnerar Builder (this) för fluent chaining. Den slutliga build()-metoden skapar målobjektet genom att skicka fältvärdena till den privata konstruktorn. Huvudklassen har en privat konstruktor som accepterar Builder. Klient: Object.builder().setField1(val1).setField2(val2).build().

När ska Builder användas — objekt med 5+ fält, varav endast 2-3 är obligatoriska. Konfigurationsobjekt (RequestConfig, DatabaseConfig). Objekt med komplex valideringslogik vid skapande. Objekt som ska vara oföränderliga (immutable) efter skapande. I Android används Builder aktivt i SDK: AlertDialog.Builder, Retrofit.Builder, OkHttpClient.Builder, NotificationCompat.Builder.

Builder i Kotlin: klassisk och DSL-implementering

Kotlin Builder har två tillvägagångssätt: klassisk Java-style Builder (genom en nästlad klass) och Kotlin-style DSL builder (genom en lambda med receiver). Java-style Builder föredras för Android-kompatibilitet och vid användning med Java-kod. DSL builder — idiomatiskt Kotlin-sätt: funktionen accepterar en lambda, inom vilken this är Builder-kontexten, där fält kan tilldelas direkt.

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

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

Kotlin DSL builder — alternativ utan nästlad klass. Builder-funktionen accepterar en lambda i kontexten av byggarobjektet. Detta är idiomatiskt för Kotlin och kräver inga write-fält. DSL builders används aktivt i Ktor Client, kotlinx.serialization, Compose (Modifier). DSL builder är inkompatibel med Java och passar inte för bibliotek med Java API.

Builder i Swift: result builders och kedjor

Swift Builder — Swift har inget inbyggt Builder-mönster, men fluent interface kan enkelt implementeras genom metoder som returnerar Self. Varje metod sätter en egenskap och returnerar self. Till skillnad från Kotlin kräver Swift ingen separat Builder-klass — objektet självt kan returneras om det är mutable i assemblieskedet. För immutable objekt används en nästlad Builder-klass analogt med 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 introducerade @resultBuilder — en språkmekanism för deklarativ uppbyggnad av strukturer. SwiftUI, AttributedString, SceneBuilder använder result builders. Detta är ett alternativ till klassisk Builder: istället för en kedja av set-metoder använder result builder ett kodblock med element som kompilatorn samlar i en array eller ett träd. @ViewBuilder i SwiftUI — det mest kända exemplet: i body kan man skriva if, switch, ForEach, och kompilatorn bygger View från villkoren.

Builder vs Telescoping Constructor: jämförelse av tillvägagångssätt

Telescoping Constructor — ett anti-mönster där en klass har flera överlagrade konstruktorer med olika parameteruppsättningar. Till exempel tre konstruktorer: HttpConfig(url), HttpConfig(url, timeout), HttpConfig(url, timeout, retries). Med ökningen av parametrar växer antalet konstruktorer exponentiellt — för n valfria fält behövs n! kombinationer. Builder löser detta problem genom att tillåta inställning av endast nödvändiga fält.

EgenskapTelescoping ConstructorBuilderKotlin named args
KodmängdExponentiell tillväxtLinjär tillväxtMinimal
LäsbarhetLåg (vilken parameter?)Hög (metod + namn)Hög (namn = värde)
OföränderlighetImmutableImmutableImmutable
Java-kompatibilitetFullständigFullständigNej (endast Kotlin)
ValideringI varje konstruktorI build() — en gångI init()

Kotlin named arguments + default values — ett elegant alternativ till Builder i rena Kotlin-projekt. Konstruktorparametrar har standardvärden, klienten skickar endast de nödvändiga: HttpConfig(baseUrl = url, timeout = 15_000). Nackdel — omöjlighet att validera obligatoriska fält vid kompilering. Builder ger obligatoriska fält genom Builder-konstruktorn (baseUrl är obligatorisk). För Java-bibliotek förblir Builder de facto standard.

Builder i Android SDK: AlertDialog, Retrofit, OkHttp

Builder i Android SDK — ett av de vanligaste mönstren i standardbiblioteket. 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().

Varför Google använder Builder — bakåtkompatibilitet. Att lägga till en ny metod i Builder bryter inte befintlig kod. Om Google hade använt en konstruktor med 20 parametrar skulle varje nytt fält kräva en ny överlagring. Builder gör det möjligt att lägga till set-metoder i åratal utan breaking changes. Till exempel lade NotificationCompat.Builder till setBubbleMetadata() i Android 11 utan att påverka befintlig kod.

Builder i Kotlin-bibliotek — Ktor (HttpClientBuilder), Coil (ImageRequest.Builder), Room (Room.databaseBuilder()), Navigation (NavOptionsBuilder). I Kotlin-projekt kombineras Builder ofta med DSL: Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build(). Mönstret förblir relevant för offentliga API:er där bakåtkompatibilitet och Java-interoperabilitet är viktiga.

Vanliga frågor

När är Builder överflödig?

Builder är överflödig för objekt med 1-3 fält — en vanlig konstruktor eller data class är mer begriplig. Även överflödig i Kotlin-projekt utan Java-interop, där named arguments + default values löser samma uppgift enklare. Builder är motiverad för 5+ fält, komplex validering eller Java API där named arguments inte är tillgängliga.

Hur skiljer sig Builder från Factory?

Builder skapar ett komplext objekt steg för steg (inställning av fält), Factory skapar ett objekt i sin helhet efter typ eller parametrar. Builder svarar på frågan «hur monterar man?», Factory — «vad ska man skapa?». Builder kombineras ofta med Factory: Factory väljer typ, Builder ställer in fälten.

Behövs Builder i SwiftUI?

I SwiftUI utförs Builder-rollen av result builders (@ViewBuilder, @SceneBuilder) och View-modifierare (.font(), .padding()). Klassisk Builder behövs inte eftersom SwiftUI använder ett deklarativt tillvägagångssätt och fluent modifiers. För UIKit-komponenter är Builder användbar: UIAlertController, URLRequest, NSAttributedString.

Hur gör man Builder trådsäker?

Builder kräver vanligtvis inte trådsäkerhet, eftersom den används i en tråd för att montera objektet. Om Builder används i en flertrådig miljö (sällsynt fall), synkronisera varje set-metod och build(). Alternativ — Immutable Builder: varje set-metod returnerar en ny Builder-instans med det ändrade fältet.

Varför använder Retrofit Builder, inte DI?

Retrofit.Builder är bibliotekets offentliga API som måste fungera utan DI-container. Builder ger konfigurationsflexibilitet (baseUrl, omvandlare, interceptorer, anpassade call-adaptere) utan beroenden av Dagger eller annan DI. Inuti applikationen kan DI skapa Retrofit en gång via Builder, men Builder själv förblir en del av Retrofit offentliga API.

Sammanfattning

  • Builder — stegvis objektkonstruktion med fluent interface
  • Kotlin Builder — klassisk (nästlad klass) och DSL (lambda med receiver)
  • Swift Builder — nästlad klass eller @resultBuilder för deklarativ kod
  • Oföränderlighet — Builder skapar immutable objekt via privat konstruktor
  • Android SDK — AlertDialog, Retrofit, OkHttp, NotificationCompat — branschstandard
  • Bakåtkompatibilitet — att lägga till fält i Builder bryter inte befintlig kod
  • Kotlin-alternativ — named arguments + default values enklare för rena Kotlin-projekt

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också