Builder-Pattern
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 67 von 87.
Das Builder-Pattern ist ein Erzeugungsmuster, das ein häufiges Problem löst: die Konstruktion komplexer Objekte mit vielen optionalen Parametern. Anstatt mehrere Konstruktoren zu erstellen oder null für nicht verwendete Parameter zu übergeben, ermöglicht es der Builder, Objekte Schritt für Schritt zu konstruieren.
Stellen Sie sich vor, Sie erstellen ein User-Objekt mit Pflichtfeldern (name, email) und optionalen Feldern (age, phone, address). Ohne einen Builder würden Sie Teleskop-Konstruktoren oder einen unübersichtlichen Konstruktor mit vielen Parametern benötigen. Das Builder-Pattern bietet einen saubereren Ansatz:
public class User {
private final String name; // erforderlich
private final String email; // erforderlich
private final int age; // optional
private final String phone; // optional
private User(UserBuilder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
this.phone = builder.phone;
}
public static class UserBuilder {
private final String name;
private final String email;
private int age;
private String phone;
public UserBuilder(String name, String email) {
this.name = name;
this.email = email;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public User build() {
return new User(this);
}
}
}Die Methoden des Builders geben this zurück und ermöglichen so Method Chaining – eine flüssige, lesbare Art, Objekte zu konstruieren:
User user = new User.UserBuilder("Alice", "alice@email.com")
.age(25)
.phone("555-1234")
.build();Beachten Sie, dass der User-Konstruktor privat ist – Objekte können nur über den Builder erstellt werden. Dieses Muster glänzt, wenn Objekte viele optionale Felder haben, was Ihren Code lesbarer und weniger fehleranfällig macht als lange Parameterlisten.
Aufgabe
EinfachLassen Sie uns ein Pizza-Bestellsystem mit dem Builder-Pattern erstellen! Anstatt sich mit einem Konstruktor herumzuschlagen, der Dutzende von Parametern für alle möglichen Beläge und Optionen entgegennimmt, erstellen Sie einen flüssigen Builder, der die Pizza-Anpassung sauber und lesbar macht.
Sie werden Ihren Code in zwei Dateien organisieren:
Pizza.java: Erstellen Sie einePizza-Klasse, die das Builder-Pattern für die Konstruktion verwendet. Ihre Pizza sollte die folgenden Felder haben:size(String) - erforderlich, repräsentiert die Pizzagrößecheese(boolean) - optional, Standardwert ist falsepepperoni(boolean) - optional, Standardwert ist falsemushrooms(boolean) - optional, Standardwert ist falseDer
Pizza-Konstruktor sollte privat sein und nur einenPizzaBuilderals Parameter akzeptieren, wobei alle Werte vom Builder in die Felder der Pizza kopiert werden.Fügen Sie eine
getDescription()-Methode hinzu, die einen String in diesem Format zurückgibt:[size] Pizza with: [toppings], wobei toppings eine kommagetrennte Liste der Beläge ist, die true sind (Cheese, Pepperoni, Mushrooms). Wenn keine Beläge ausgewählt sind, sollte der Belag-Teil einfachno toppingslauten.Erstellen Sie eine statische innere Klasse
PizzaBuildermit:- Einem Konstruktor, der den erforderlichen
size-Parameter entgegennimmt - Methoden
cheese(),pepperoni()undmushrooms(), die jeweils den entsprechenden Boolean auf true setzen undthisfür das Chaining zurückgeben - Einer
build()-Methode, die eine neuePizzazurückgibt
- Einem Konstruktor, der den erforderlichen
Main.java: Demonstrieren Sie Ihren Pizza-Builder in Aktion! Sie erhalten vier Eingaben: die Pizzagröße (String) und drei yes/no-Werte (Strings), die angeben, ob Käse, Peperoni bzw. Pilze hinzugefügt werden sollen.Erstellen Sie einen
PizzaBuildermit der angegebenen Größe. Verketten Sie dann basierend auf jeder yes/no-Eingabe die entsprechenden Belag-Methoden. Wenn die Eingabe"yes"ist, rufen Sie diese Belag-Methode auf; wenn sie"no"ist, überspringen Sie diese. Rufen Sie schließlichbuild()auf, um Ihre Pizza zu erstellen.Geben Sie das Ergebnis des Aufrufs von
getDescription()für Ihre fertige Pizza aus.
Sie erhalten vier Eingaben in der Reihenfolge: size (String), add cheese (String: "yes" oder "no"), add pepperoni (String: "yes" oder "no"), add mushrooms (String: "yes" oder "no").
Zum Beispiel wäre bei den Eingaben Large, yes, no, yes Ihre Ausgabe: Large Pizza with: Cheese, Mushrooms
Beachten Sie, wie das Builder-Pattern es Ihnen ermöglicht, Pizzas mit jeder beliebigen Kombination von Belägen zu konstruieren, ohne separate Konstruktoren für jede Möglichkeit zu benötigen!
Spickzettel
Das Builder-Muster (Erbauer-Muster) ist ein Erzeugungsmuster zur Konstruktion komplexer Objekte mit vielen optionalen Parametern. Es vermeidet "Telescoping Constructors" und lange Parameterlisten, indem Objekte Schritt für Schritt aufgebaut werden.
Struktur
Das Muster besteht aus:
- Einer Klasse mit einem privaten Konstruktor, der nur einen Builder akzeptiert
- Einer statischen inneren Builder-Klasse, die das Objekt konstruiert
- Builder-Methoden, die
thisfür Method Chaining (Methodenverkettung) zurückgeben - Einer
build()-Methode, die das finale Objekt erstellt
Implementierungsbeispiel
public class User {
private final String name; // erforderlich
private final String email; // erforderlich
private final int age; // optional
private final String phone; // optional
private User(UserBuilder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
this.phone = builder.phone;
}
public static class UserBuilder {
private final String name;
private final String email;
private int age;
private String phone;
public UserBuilder(String name, String email) {
this.name = name;
this.email = email;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public User build() {
return new User(this);
}
}
}Verwendung mit Method Chaining
User user = new User.UserBuilder("Alice", "alice@email.com")
.age(25)
.phone("555-1234")
.build();Das Builder-Muster ist ideal, wenn Objekte viele optionale Felder haben, da es im Vergleich zu Konstruktoren mit zahlreichen Parametern lesbaren und wartbaren Code bietet.
Probier es selbst
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Eingaben lesen
String size = scanner.nextLine();
String addCheese = scanner.nextLine();
String addPepperoni = scanner.nextLine();
String addMushrooms = scanner.nextLine();
// TODO: Erstelle einen PizzaBuilder mit der angegebenen Größe
// TODO: Verkette die Topping-Methoden basierend auf den yes/no Eingaben
// TODO: Baue die Pizza und gib ihre Beschreibung aus
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenFelder (Attribute)Konstruktor-MethodeKonstruktor-ÜberladungRückblick – Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (extends)Das super-SchlüsselwortMethoden überschreiben (@Override)Konstruktor-VerkettungDie Object-KlasseEinfache & mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-InterfaceZusammenfassung – Benutzerdefiniertes Sortieren2Zugriffsmodifikatoren & Kapselung
Überblick über ZugriffsebenenGetter- und Setter-MethodenInformation HidingDas final-SchlüsselwortRückblick – Bankkonto-Manager5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenZusammenfassung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, geschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Teil 1
Einführung in Design PatternsSingleton-PatternFactory-PatternBuilder-PatternObserver-PatternStrategy-Pattern14Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung3Klasseneigenschaften & Statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Zusammenfassung – Zähler & Utility6Interfaces & Abstrakte Klassen
Einführung in InterfacesInterfaces implementierenImplementierung mehrerer InterfacesDefault- & statische Methoden in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesZusammenfassung - Zahlungssystem