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.