Design Patterns in Android – Builder

Builder

Das Builder Pattern vereinfacht die Erstellung von Objekten auf eine sehr saubere und lesbare Weise. Es ist sehr hilfreich, wenn wir einige Modellklassen mit vielen Parametern haben. Wir können einige von ihnen optional oder erforderlich machen, und wir zwingen den Benutzer nicht, eine bestimmte Reihenfolge zu verwenden (wie im Konstruktor). Durch die Verwendung des Builder-Musters erhalten wir eine elegante Kette von Methoden. Die gebräuchlichste Anwendung ist die Klasse AlertDialog.Builder():

new AlertDialog.Builder(this)
.setTitle("Design Patterns")
.setMessage("Builder is awesome")
.create();

Wie können wir die Builder-Klasse für unseren eigenen Gebrauch erstellen?

Builder in der Praxis

Angenommen, wir haben eine Modellklasse für den Benutzer:

public class User {
private String firstName;
private String lastName;
private int age;
}

Und anstatt Objekte dieser Klasse mit Hilfe von Konstruktoren zu erstellen, wollen wir sie mit dem Builder-Muster wie folgt erstellen:

new User.Builder()
.setFirstName("Leonardo")
.setLastName("da Vinci")
.setAge(67)
.create();

Wie können wir das tun? Erstens müssen wir die Klasse Builder innerhalb der Klasse User erstellen, die die Methoden zum Erstellen unseres Objekts enthält. Der Schlüssel zur Verkettung von Methoden ist, dass die Builder-Methoden die Klasse Builder zurückgeben. Schau dir das Beispiel an:

static class Builder {
private String firstName;
private String lastName;
private int age;
public Builder setFirstName(final String firstName) {
this.firstName = firstName;
return this;
}
public Builder setLastName(final String lastName) {
this.lastName = lastName;
return this;
}
public Builder setAge(final int age) {
this.age = age;
return this;
}
public User create() {
return new User(this);
}
}

Für jeden Parameter haben wir einen Setter – der Unterschied ist, dass diese Methoden den Typ Builder zurückgeben. Am Ende haben wir eine Methode, die den Konstruktor der Klasse User verwendet und das Objekt User zurückgibt – hier ist der Ort, an dem unser Durcheinander versteckt ist.

Dann müssen wir einen Konstruktor mit allen Parametern in der Modellklasse User erstellen:

public class User {
private String firstName;
private String lastName;
private int age;
private User(final Builder builder) {
firstName = builder.firstName;
lastName = builder.lastName;
age = builder.age;
}
}

Wichtig ist hier, dass der User-Konstruktor privat ist, so dass auf ihn nicht von der anderen Klasse zugegriffen werden kann und wir Builder verwenden müssen, um ein neues Objekt zu erstellen.

Natürlich können wir einige der Parameter erforderlich machen (im Moment sind alle optional), indem wir unsere create()-Methode modifizieren und einige Ausnahmen auslösen, z.B.:

public User create() {
User user = new User(firstName, lastName, age);
if (user.firstName.isEmpty()) {
throw new IllegalStateException(
"First name can not be empty!");
}
return user;
}

Das war’s. Auf diese Weise haben wir unsere User.Builder() Klasse erstellt!

Builder – protip

Wenn Sie geduldig genug waren, den ganzen Blogbeitrag durchzuarbeiten, habe ich einen Tipp für Sie bezüglich des Builder-Musters: Sie können die gesamte Builder-Klasse mit IntelliJ generieren!

Alles, was Sie tun müssen, ist, den Cursor auf den Konstruktor in Ihrer Klasse zu setzen und Refactor -> Replace Constructor with Builder im Kontextmenü zu wählen. Die Builder-Klasse mit allen Methoden wird automatisch generiert und ist sofort einsatzbereit.

Sie können hier mehr lesen: IntelliJ: Ersetze Konstruktor durch Builder

Fazit

Das Builder-Muster ist ein guter Ansatz, nicht nur für Modellklassen, sondern für jedes Objekt, das mehr als drei oder vier Parameter hat. Mit ein wenig zusätzlicher Arbeit können wir die Lesbarkeit unseres Codes erhöhen. Design Patterns sind als Best Practice anerkannt, so dass es von großem Vorteil ist, wenn man einige von ihnen kennt, und Builder ist ein gutes Muster, um damit zu beginnen.