Kreative Designmuster in Kotlin: Builder

1. Einleitung

In diesem kurzen Artikel erfahren Sie, wie Sie das Builder-Entwurfsmuster in Kotlin implementieren.

2. Builder-Muster

Das Builder-Muster wird häufig verwendet, aber nur selten selbst erstellt.

Es ist großartig, Objekte zu erstellen, die viele Parameter enthalten können, und wenn wir das Objekt nach Abschluss der Erstellung unveränderlich machen möchten.

Weitere Informationen finden Sie in unserem Tutorial zu Kreativdesignmustern hier.

3. Implementierung

Kotlin bietet viele nützliche Funktionen wie benannte und Standardparameter, apply () und Datenklasse, die die Verwendung der klassischen Builder-Musterimplementierung vermeiden.

Aus diesem Grund sehen wir zuerst eine klassische Implementierung im Java-Stil und dann eine Kurzform im Kotlin-Stil.

3.1. Implementierung im Java-Stil

Beginnen wir mit der Erstellung einer Klasse - FoodOrder -, die schreibgeschützte Felder enthält, da äußere Objekte nicht direkt darauf zugreifen sollen:

class FoodOrder private constructor(builder: FoodOrder.Builder) { val bread: String? val condiments: String? val meat: String? val fish: String? init { this.bread = builder.bread this.condiments = builder.condiments this.meat = builder.meat this.fish = builder.fish } class Builder { // builder code } }

Beachten Sie, dass der Konstruktor privat ist, sodass nur die verschachtelte Builder- Klasse darauf zugreifen kann.

Lassen Sie uns nun die verschachtelte Klasse erstellen, die zum Erstellen von Objekten verwendet wird:

class Builder { var bread: String? = null private set var condiments: String? = null private set var meat: String? = null private set var fish: String? = null private set fun bread(bread: String) = apply { this.bread = bread } fun condiments(condiments: String) = apply { this.condiments = condiments } fun meat(meat: String) = apply { this.meat = meat } fun fish(fish: String) = apply { this.fish = fish } fun build() = FoodOrder(this) } 

Wie wir sehen, hat unser Builder dieselben Felder wie die äußere Klasse. Für jedes äußere Feld haben wir eine passende Setter-Methode.

Wenn wir ein oder mehrere Pflichtfelder haben, anstatt Setter-Methoden zu verwenden, lassen Sie sie von einem Konstruktor festlegen.

Beachten Sie, dass wir die Apply- Funktion verwenden, um den Ansatz des fließenden Designs zu unterstützen.

Schließlich rufen wir mit der Build- Methode den FoodOrder- Konstruktor auf.

3.2. Implementierung im Kotlin-Stil

Um Kotlin voll ausnutzen zu können, müssen wir einige Best Practices überdenken, an die wir uns in Java gewöhnt haben. Viele von ihnen können durch bessere Alternativen ersetzt werden.

Mal sehen, wie wir idiomatischen Kotlin-Code schreiben können:

class FoodOrder private constructor( val bread: String?, val condiments: String?, val meat: String?, val fish: String?) { data class Builder( var bread: String? = null, var condiments: String? = null, var meat: String? = null, var fish: String? = null) { fun bread(bread: String) = apply { this.bread = bread } fun condiments(condiments: String) = apply { this.condiments = condiments } fun meat(meat: String) = apply { this.meat = meat } fun fish(fish: String) = apply { this.fish = fish } fun build() = FoodOrder(bread, condiments, meat, fish) } }

Kotlin wird mit benannten und Standardparametern geliefert, um die Anzahl der Überladungen zu minimieren und die Lesbarkeit des Funktionsaufrufs zu verbessern.

Wir können auch die Datenklassenstruktur von Kotlin nutzen, die wir in einem anderen Tutorial hier genauer untersuchen.

Schließlich ist apply () ebenso wie bei der Implementierung im Java-Stil nützlich, um fließende Setter zu implementieren.

4. Anwendungsbeispiel

Lassen Sie uns kurz einen Blick darauf werfen, wie FoodOrder- Objekte mithilfe dieser Builder- Musterimplementierung erstellt werden:

val foodOrder = FoodOrder.Builder() .bread("white bread") .meat("bacon") .condiments("olive oil") .build() 

5. Schlussfolgerung

Das Builder-Muster löst ein sehr häufiges Problem bei der objektorientierten Programmierung, wie ein unveränderliches Objekt flexibel erstellt werden kann, ohne viele Konstruktoren zu schreiben.

Wenn wir einen Bauunternehmer in Betracht ziehen, sollten wir uns darauf konzentrieren, ob die Konstruktion komplex ist oder nicht. Wenn wir zu einfache Konstruktionsmuster haben, kann der Aufwand für die Erstellung unseres flexiblen Builder-Objekts den Nutzen bei weitem übersteigen.

Wie immer ist der Code auf Github verfügbar.