Wenn du schon einmal ein Objekt mit vielen Parametern im Konstruktor hattest, weißt du, wie schnell der Code unübersichtlich wird. Besonders bei Klassen, die viele optionale Eigenschaften haben, kann das Lesen und Erstellen solcher Objekte mühsam werden. Genau hier hilft das Builder Pattern. Es sorgt dafür, dass dein Code besser lesbar, wartbarer und weniger fehleranfällig wird.
Stell dir vor, du möchtest eine Klasse Person erstellen. Sie soll den Namen, das Alter, die Adresse und optional auch eine Telefonnummer enthalten. Ohne Builder würde man das so machen:
public class Person {
private String name;
private int alter;
private String adresse;
private String telefonnummer;
public Person(String name, int alter, String adresse, String telefonnummer) {
this.name = name;
this.alter = alter;
this.adresse = adresse;
this.telefonnummer = telefonnummer;
}
public Person(String name, int alter, String adresse) {
this(name, alter, adresse, null);
}
public Person(String name, int alter) {
this(name, alter, null, null);
}
public void printInfo() {
System.out.println("Name: " + name);
System.out.println("Alter: " + alter);
System.out.println("Adresse: " + adresse);
System.out.println("Telefonnummer: " + telefonnummer);
}
}
So weit, so gut. Aber was passiert, wenn in Zukunft noch mehr Felder hinzukommen – zum Beispiel E-Mail, Beruf oder Hobbys? Dann wächst die Anzahl der Konstruktoren schnell an. Man spricht vom sogenannten Telescoping Constructor Problem. Jeder neue Parameter führt zu einem neuen Konstruktor, und der Code wird unübersichtlich.
Das Builder Pattern löst dieses Problem, indem es den Erstellungsprozess von Objekten in eine eigene Klasse auslagert – den Builder. Dadurch bleibt der Konstruktor der eigentlichen Klasse privat, und das Objekt wird schrittweise über Methoden des Builders aufgebaut.
Hier siehst du, wie das Ganze aussehen kann:
public class Person {
private String name;
private int alter;
private String adresse;
private String telefonnummer;
private Person(Builder builder) {
this.name = builder.name;
this.alter = builder.alter;
this.adresse = builder.adresse;
this.telefonnummer = builder.telefonnummer;
}
public void printInfo() {
System.out.println("Name: " + name);
System.out.println("Alter: " + alter);
System.out.println("Adresse: " + adresse);
System.out.println("Telefonnummer: " + telefonnummer);
}
public static class Builder {
private String name;
private int alter;
private String adresse;
private String telefonnummer;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder alter(int alter) {
this.alter = alter;
return this;
}
public Builder adresse(String adresse) {
this.adresse = adresse;
return this;
}
public Builder telefonnummer(String telefonnummer) {
this.telefonnummer = telefonnummer;
return this;
}
public Person build() {
return new Person(this);
}
}
}
Das ist auf den ersten Blick etwas mehr Code, aber dafür wird das Erstellen von Objekten deutlich einfacher und flexibler. Der Builder gibt dir eine klare Struktur und macht den Code gut lesbar.
Mit der obigen Klasse kannst du nun ganz elegant Objekte erstellen, ohne dich durch lange Konstruktorlisten zu kämpfen:
public class Main {
public static void main(String[] args) {
Person person = new Person.Builder()
.name("Max Mustermann")
.alter(30)
.adresse("Musterstrasse 12")
.telefonnummer("01234-56789")
.build();
person.printInfo();
}
}
Ausgabe:
Name: Max Mustermann
Alter: 30
Adresse: Musterstrasse 12
Telefonnummer: 01234-56789
Der Code liest sich fast wie ein Satz in natürlicher Sprache. Jeder Methodenaufruf beschreibt, welches Feld gesetzt wird. Besonders schön ist, dass du die Reihenfolge selbst bestimmen kannst und optionale Felder einfach weglassen darfst.
Du kannst beim Builder ganz leicht entscheiden, welche Werte gesetzt werden. Wenn du zum Beispiel keine Telefonnummer angeben möchtest, lässt du sie einfach weg:
Person person = new Person.Builder()
.name("Lisa Musterfrau")
.alter(25)
.adresse("Beispielweg 5")
.build();
Ausgabe:
Name: Lisa Musterfrau
Alter: 25
Adresse: Beispielweg 5
Telefonnummer: null
Wie du siehst, ist das völlig in Ordnung. Der Builder setzt nur das, was du vorgibst. Alles andere bleibt auf dem Standardwert (in diesem Fall null oder 0).
Ein großer Vorteil ist, dass du im Builder auch Prüfungen einbauen kannst. Wenn du zum Beispiel sicherstellen willst, dass das Alter nicht negativ ist, kannst du das direkt im build()-Aufruf prüfen:
public Person build() {
if (alter < 0) {
throw new IllegalArgumentException("Alter darf nicht negativ sein");
}
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Name darf nicht leer sein");
}
return new Person(this);
}
Damit stellst du sicher, dass kein fehlerhaftes Objekt erzeugt wird. Das ist besonders in größeren Projekten hilfreich, wo du viele komplexe Datenmodelle hast.
Das Builder Pattern ist nicht immer nötig. Wenn du eine Klasse mit nur ein oder zwei Attributen hast, reicht oft ein normaler Konstruktor oder Setter. Aber sobald du viele optionale Parameter oder komplexe Objekte hast, ist der Builder fast immer die bessere Wahl. Besonders bei Immutable Objects (also Objekten, deren Felder nach der Erstellung nicht mehr verändert werden sollen) spielt der Builder seine Stärken aus.
Angenommen, du möchtest eine Klasse Auto erstellen, die verschiedene optionale Eigenschaften haben kann – Marke, Modell, Baujahr, Farbe und ob sie ein Elektroauto ist. Mit dem Builder sieht das so aus:
public class Auto {
private String marke;
private String modell;
private int baujahr;
private String farbe;
private boolean elektro;
private Auto(Builder builder) {
this.marke = builder.marke;
this.modell = builder.modell;
this.baujahr = builder.baujahr;
this.farbe = builder.farbe;
this.elektro = builder.elektro;
}
public void printInfo() {
System.out.println(marke + " " + modell + " (" + baujahr + ")");
System.out.println("Farbe: " + farbe);
System.out.println("Elektro: " + (elektro ? "Ja" : "Nein"));
}
public static class Builder {
private String marke;
private String modell;
private int baujahr;
private String farbe;
private boolean elektro;
public Builder marke(String marke) { this.marke = marke; return this; }
public Builder modell(String modell) { this.modell = modell; return this; }
public Builder baujahr(int baujahr) { this.baujahr = baujahr; return this; }
public Builder farbe(String farbe) { this.farbe = farbe; return this; }
public Builder elektro(boolean elektro) { this.elektro = elektro; return this; }
public Auto build() {
return new Auto(this);
}
}
}
Und die Verwendung ist wieder ganz einfach:
public class Main {
public static void main(String[] args) {
Auto auto = new Auto.Builder()
.marke("Tesla")
.modell("Model 3")
.baujahr(2022)
.farbe("Weiss")
.elektro(true)
.build();
auto.printInfo();
}
}
Ausgabe:
Tesla Model 3 (2022)
Farbe: Weiss
Elektro: Ja
Das Builder Pattern ist ein mächtiges Werkzeug, um komplexe Objekte übersichtlich und sicher zu erstellen. Es hilft dir, sauberen, gut lesbaren Code zu schreiben und Fehler beim Erstellen von Objekten zu vermeiden. Besonders in Java, wo es keine benannten Parameter wie in manchen anderen Sprachen gibt, ist der Builder eine elegante und bewährte Lösung.
Wenn du dich also das nächste Mal dabei ertappst, mehrere überladene Konstruktoren zu schreiben oder viele optionale Parameter benötigst – denk an den Builder. Er sorgt für klaren, verständlichen und professionellen Code.

Hi, ich bin Marcel!
Als Fachinformatiker für Anwendungsentwicklung und IHK-geprüfter Ausbilder teile ich auf meinem Blog Grundlagen- und Fortgeschrittenen-Wissen für angehende Entwickler*innen und Interessierte, sowie weitere spannende Themen aus der IT.