Builder — Grundlagen des Builder-Musters in der mobilen Entwicklung

Autor: IT Sectr Veröffentlicht: 2026-02-17 Lesezeit: 7 Min.

Builder — ein Erzeugungsmuster, das die schrittweise Erstellung komplexer Objekte ermöglicht. Im Gegensatz zu einem Konstruktor mit einem Dutzend Parametern setzt Builder ein Objekt durch eine Kette von Aufrufen zusammen, von denen jeder ein Feld konfiguriert. Das Muster ist besonders nützlich für Objekte mit vielen optionalen Parametern: Netzwerkclient-Konfiguration, Datenbankeinstellungen, Builder für Alarme und Navigation. Mehr Details auf Refactoring Guru: Builder.

Die wichtigsten Punkte

  • Builder — schrittweise Objektkonstruktion mit Trennung von Prozess und Ergebnis
  • Fluent interface — Kette von set()/with()-Aufrufen für bequeme Konfiguration
  • Unveränderlichkeit — Builder erstellt ein fertiges Objekt, das keine Setter benötigt
  • Rückwärtskompatibilität — neue Felder können zu Builder hinzugefügt werden, ohne Clients zu brechen
  • Kotlin DSL vs Builder — Kotlin bietet type-safe builders als Alternative an

Was ist Builder: das Wesen des Builder-Musters?

Builder — ein GoF-Erzeugungsmuster, das die Konstruktion eines komplexen Objekts von seiner Darstellung trennt. Derselbe Konstruktionsprozess kann verschiedene Darstellungen erzeugen. Builder ist nützlich, wenn ein Objekt viele optionale Parameter hat und ein Konstruktor mit zehn Feldern unlesbar und unflexibel ist. Das Muster löst auch das Telescoping-Constructor-Antimuster, bei dem die Anzahl der Konstruktorüberladungen exponentiell wächst.

Builder-Struktur umfasst eine innere statische Builder-Klasse mit Feldern, die die Felder der Hauptklasse widerspiegeln. Jede set-Methode gibt Builder (this) für fließende Verkettung zurück. Die finale build()-Methode erstellt das Zielobjekt, indem sie Feldwerte an einen privaten Konstruktor übergibt. Die Hauptklasse hat einen privaten Konstruktor, der einen Builder akzeptiert. Client: Object.builder().setField1(val1).setField2(val2).build().

Wann Builder verwenden — Objekte mit 5+ Feldern, von denen nur 2-3 erforderlich sind. Konfigurationsobjekte (RequestConfig, DatabaseConfig). Objekte mit komplexer Validierungslogik bei der Erstellung. Objekte, die nach der Erstellung unveränderlich (immutable) sein müssen. In Android wird Builder aktiv im SDK verwendet: AlertDialog.Builder, Retrofit.Builder, OkHttpClient.Builder, NotificationCompat.Builder.

Builder in Kotlin: klassische und DSL-Implementierung

Builder in Kotlin hat zwei Ansätze: klassischen Java-Stil Builder (über eine verschachtelte Klasse) und Kotlin-Stil DSL builder (über ein Lambda mit Empfänger). Der Java-Stil Builder ist für Android-Kompatibilität und bei Verwendung mit Java-Code vorzuziehen. Der DSL builder ist die idiomatische Kotlin-Methode: eine Funktion akzeptiert ein Lambda, innerhalb dessen this der Builder-Kontext ist, in dem Felder direkt zugewiesen werden können.

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

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

Kotlin DSL builder — eine Alternative ohne verschachtelte Klasse. Eine Builder-Funktion akzeptiert ein Lambda im Kontext eines Builder-Objekts. Dies ist idiomatisch für Kotlin und erfordert keine write-Felder. DSL builders werden aktiv in Ktor Client, kotlinx.serialization, Compose (Modifier) verwendet. DSL builder ist mit Java inkompatibel und nicht für Bibliotheken mit Java-API geeignet.

Builder in Swift: result builders und Ketten

Builder in Swift — Swift hat kein eingebautes Builder-Muster, aber eine fließende Schnittstelle lässt sich leicht durch Methoden implementieren, die Self zurückgeben. Jede Methode konfiguriert eine Eigenschaft und gibt self zurück. Anders als Kotlin erfordert Swift keine separate Builder-Klasse — Sie können das Objekt selbst zurückgeben, wenn es während der Assemblierung veränderbar ist. Für unveränderliche Objekte wird eine verschachtelte Builder-Klasse ähnlich wie bei Kotlin verwendet.

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 führte @resultBuilder ein — ein Sprachmechanismus für deklarativen Strukturaufbau. SwiftUI, AttributedString, SceneBuilder verwenden result builders. Dies ist eine Alternative zum klassischen Builder: statt einer Kette von set-Methoden verwendet result builder einen Codeblock mit Elementen, die der Compiler zu einem Array oder Baum zusammenstellt. @ViewBuilder in SwiftUI ist das bekannteste Beispiel: innerhalb von body können if, switch, ForEach geschrieben werden, und der Compiler baut aus den Bedingungen eine View.

Builder vs Telescoping Constructor: Ansatzvergleich

Telescoping Constructor — ein Antimuster, bei dem eine Klasse viele überladene Konstruktoren mit verschiedenen Parametersätzen hat. Zum Beispiel drei Konstruktoren: HttpConfig(url), HttpConfig(url, timeout), HttpConfig(url, timeout, retries). Mit wachsenden Parametern steigt die Anzahl der Konstruktoren exponentiell — für n optionale Felder werden n! Kombinationen benötigt. Builder löst dieses Problem, indem er nur die benötigten Felder angeben lässt.

EigenschaftTelescoping ConstructorBuilderKotlin named args
Code-MengeExponentielles WachstumLineares WachstumMinimal
LesbarkeitNiedrig (welcher Parameter ist was?)Hoch (Methode + Name)Hoch (Name = Wert)
UnveränderlichkeitUnveränderlichUnveränderlichUnveränderlich
Java-KompatibilitätVollständigVollständigKeine (nur Kotlin)
ValidierungIn jedem KonstruktorIn build() — einmalIn init()

Kotlin named arguments + Standardwerte — eine elegante Alternative zu Builder in reinen Kotlin-Projekten. Konstruktorparameter haben Standardwerte, der Client übergibt nur die benötigten: HttpConfig(baseUrl = url, timeout = 15_000). Der Nachteil ist die Unfähigkeit, erforderliche Felder zur Kompilierzeit zu validieren. Builder bietet erforderliche Felder durch den Builder-Konstruktor (baseUrl ist erforderlich). Für Java-Bibliotheken bleibt Builder der De-facto-Standard.

Builder im Android SDK: AlertDialog, Retrofit, OkHttp

Builder im Android SDK — eines der häufigsten Muster in der Standardbibliothek. 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().

Warum Google Builder verwendet — Rückwärtskompatibilität. Das Hinzufügen einer neuen Methode zu Builder bricht bestehenden Code nicht. Wenn Google einen Konstruktor mit 20 Parametern verwendet hätte, würde jedes neue Feld eine neue Überladung erfordern. Builder erlaubt das Hinzufügen von set-Methoden über Jahre ohne breaking changes. Beispielsweise fügte NotificationCompat.Builder in Android 11 setBubbleMetadata() hinzu, ohne bestehenden Code zu beeinträchtigen.

Builder in Kotlin-Bibliotheken — Ktor (HttpClientBuilder), Coil (ImageRequest.Builder), Room (Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build()), Navigation (NavOptionsBuilder). In Kotlin-Projekten wird Builder oft mit DSL kombiniert: Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build(). Das Muster bleibt für öffentliche APIs relevant, bei denen Rückwärtskompatibilität und Java-Interop wichtig sind.

Häufig gestellte Fragen

Wann ist Builder übertrieben?

Builder ist für Objekte mit 1-3 Feldern übertrieben — ein normaler Konstruktor oder eine data class ist verständlicher. Auch in Kotlin-Projekten ohne Java-Interop ist es übertrieben, wo named arguments + Standardwerte die gleiche Aufgabe einfacher lösen. Builder ist bei 5+ Feldern, komplexer Validierung oder Java-APIs gerechtfertigt, wo named arguments nicht verfügbar sind.

Wie unterscheidet sich Builder von Factory?

Builder erstellt ein komplexes Objekt schrittweise (Feldkonfiguration), Factory erstellt ein Objekt vollständig nach Typ oder Parametern. Builder beantwortet die Frage «wie zusammenbauen?», Factory beantwortet «was erstellen?». Builder wird oft mit Factory kombiniert: Factory wählt den Typ, Builder konfiguriert die Felder.

Wird Builder in SwiftUI benötigt?

In SwiftUI übernehmen result builders (@ViewBuilder, @SceneBuilder) und View-Modifikatoren (.font(), .padding()) die Rolle von Builder. Klassischer Builder wird nicht benötigt, da SwiftUI einen deklarativen Ansatz und fließende Modifikatoren verwendet. Für UIKit-Komponenten ist Builder nützlich: UIAlertController, URLRequest, NSAttributedString.

Wie macht man Builder threadsicher?

Builder benötigt normalerweise keine Threadsicherheit, da er in einem einzelnen Thread zum Zusammenbau eines Objekts verwendet wird. Wenn Builder in einer Multithread-Umgebung (seltener Fall) verwendet wird, synchronisieren Sie jede set-Methode und build(). Alternative — Immutable Builder: jede set-Methode gibt eine neue Builder-Instanz mit dem geänderten Feld zurück.

Warum verwendet Retrofit Builder statt DI?

Retrofit.Builder ist eine öffentliche Bibliotheks-API, die ohne DI-Container funktionieren muss. Builder bietet Konfigurationsflexibilität (baseUrl, Konverter, Interceptors, benutzerdefinierte Call-Adapter) ohne Abhängigkeiten von Dagger oder anderen DI-Frameworks. Innerhalb einer Anwendung kann DI Retrofit einmal durch Builder erstellen, aber Builder selbst bleibt Teil der öffentlichen Retrofit-API.

Zusammenfassung

  • Builder — schrittweise Objektkonstruktion mit fließender Schnittstelle
  • Kotlin Builder — klassisch (verschachtelte Klasse) und DSL (Lambda mit Empfänger)
  • Swift Builder — verschachtelte Klasse oder @resultBuilder für deklarativen Code
  • Unveränderlichkeit — Builder erstellt unveränderliche Objekte durch privaten Konstruktor
  • Android SDK — AlertDialog, Retrofit, OkHttp, NotificationCompat — Industriestandard
  • Rückwärtskompatibilität — Hinzufügen von Feldern zu Builder bricht bestehenden Code nicht
  • Kotlin-Alternative — named arguments + Standardwerte einfacher für reine Kotlin-Projekte

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch