Was ist das Builder Pattern?

Das Builder Pattern gehört zu den Design Patterns – vielfach bewährten Vorlagen zur Lösung von Programmieraufgaben in der objektorientierten Programmierung. Sie erleichtern den Entwicklern die Programmierung, da nicht jeder wiederholt auftretende Schritt erneut als Programmroutine erdacht werden muss, sondern auf eine bereits etablierte Lösung zurückgegriffen werden kann. Diese Software-Elemente gehen auf das 1994 erschienene Buch „Entwurfsmuster. Elemente wiederverwendbarer objektorientierter Software“ von vier US-Software-Entwicklern zurück – bekannt als die Viererbande (engl. „Gang of Four“, abgekürzt GoF). Unser Ratgeber stellt Ihnen die wesentlichen Aspekte des Erbauer-Entwurfsmusters mit einem praktischen Beispiel vor.

Das Builder Pattern im Detail

Das Builder Pattern gehört zur Gruppe der Erzeugungsmuster aus den Design Patterns. Es verbessert sowohl die Sicherheit bei der Konstruktion als auch die Lesbarkeit des Programmcodes. Das Ziel des Erbauer-Entwurfsmusters ist, dass ein Objekt nicht mit den bekannten Konstruktoren erstellt wird, sondern mittels einer Hilfsklasse.

Zitat

„Separate the construction of a complex object from its representation so that the same construction process can create different representations.“

Übersetzung: „Trennen Sie die Konstruktion eines komplexen Objekts von seiner Darstellung, so dass derselbe Konstruktionsprozess verschiedene Darstellungen erzeugen kann.“ (Übers. von IONOS)

– Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (= „Gang of Four“)

Quelle: Design Patterns: Elements of Reusable Object-Oriented Software (Englisch) 1. Auflage, Herausgeber: Addison-Wesley Professional; 1. Auflage (10. November 1994)

Im Builder Design Pattern werden vier Akteure unterschieden:

  • Direktor: Dieser Akteur konstruiert das komplexe Objekt, indem er die Schnittstelle des Erbauers verwendet. Er kennt die Anforderungen an die Arbeitsreihenfolge des Erbauers. Beim Direktor wird die Konstruktion eines Objekts vom Kunden („Auftraggeber“) entkoppelt.
  • Erbauer: Hält eine Schnittstelle zur Erzeugung der Bestandteile eines komplexen Objekts (bzw. Produkts) bereit.
  • Konkreter Erbauer: Dieser Akteur erzeugt die Teile des komplexen Objekts und definiert (und verwaltet) die Repräsentation des Objekts und hält eine Schnittstelle zur Ausgabe des Objekts vor.
  • Produkt: Das Ergebnis der „Tätigkeit“ des Builder Patterns, also das zu konstruierende komplexe Objekt.

Beim Direktor geschieht der entscheidende Vorgang des Erbauer-Musters, die Trennung der Herstellung eines Objekts/Produkts vom Auftraggeber.

Das Builder Pattern in UML-Darstellung

Für die grafische Darstellung von Programmierabläufen wird die vereinheitlichte Modellierungssprache, kurz UML (Unified Modeling Language), genutzt. Die Grafik zeigt, dass das Erbauer-Muster aus mehreren, miteinander agierenden Objekten besteht.

Plus und Minus des Erbauer-Musters

Vorteile des Erbauer-Entwurfsmusters

Die Konstruktion (das Erbauen) und die Repräsentation (die Ausgabe) werden voneinander isoliert eingebunden. Die internen Repräsentationen der Erbauer sind vor dem Direktor „versteckt“. Neue Repräsentationen können leicht durch neue konkrete Erbauerklassen eingefügt werden. Der Prozess der Konstruktion wird vom Direktor als explizite Stelle gesteuert. Müssen dabei Änderungen vorgenommen werden, ist das ohne Rückfragen beim Klienten möglich.

Nachteile des Builder Patterns

Es besteht eine enge Kopplung zwischen Produkt, konkretem Erbauer und den am Konstruktionsprozess beteiligten Klassen, so dass Änderungen am grundsätzlichen Prozess schwierig sein können. Das Erbauen (Konstruktion) der Objekte erfordert oft Wissen über deren spezielle Verwendung und ihre Umgebung. Die Nutzung von bekannten Patterns, so auch des Erbauer-Entwurfsmusters, können Programmierer dazu verleiten, einfachere und vielleicht elegantere Lösungen zu übersehen. Letztlich gilt das Erbauer-Muster unter Programmierern als eines der weniger wichtigen Entwurfsmuster.

Wo kommt das Builder Pattern zum Einsatz?

Eine Möglichkeit, das Erbauer-Entwurfsmuster zu verdeutlichen, ist ein vereinfacht dargestelltes Restaurant, in dem ein Gast ein Menü bestellt. Die verschiedenen Akteure des Restaurants agieren nach dem Eingang der Bestellung, um diese auszuführen. Der gesamte Vorgang bis zum Erhalt des bestellten Menüs spielt sich „hinter den Kulissen“ ab. Der Gast sieht z. B. nicht, was in der Küche geschieht, um seine Bestellung auszuführen – er bekommt das Ergebnis an seinem Tisch serviert (in Programmiersprache: ausgedruckt = print).

Die folgenden Code-Abschnitte stellen alle Akteure des Builder Patterns separat vor.

Das Objekt, das komplette Menü, ist anfänglich leer; mit der Bestellung wird es mit Inhalten gefüllt:

public class Menue {
	private String starter = "Keine Vorspeise";
	private String maincourse = "Kein Hauptgericht";
	private String dessert = "Keine Nachspeise";
	private String drink = "Kein Getränk";
	public void setVorspeise(String starter) {
		this.starter = starter;
	}
	public void setHauptgericht (String maincourse) {
		this.maincourse = maincourse;
	}
	public void setNachspeise(String dessert) {
		this.dessert = dessert;
	}
	public void setGetraenk(String drink) {
		this.drink = drink;
	}
	public void print() {
		System.out.println(
			"Das Menue ist fertig! " + "\n" +
			" – Vorspeise: " + starter +
			" – Hauptgericht: " + maincourse +
			" – Nachspeise: " + dessert +
			" – Getränk: " + drink);
	}
}

Der Direktor stellt die „Umgebung“ bereit, dass überhaupt ein Menü für den Gast hergestellt – erbaut – werden kann. Diese Umgebung ist für jeden Gast zugänglich. Der Gast kommuniziert ausschließlich mit dem Direktor, so dass ihm die eigentliche Erzeugung verborgen bleibt:

public class MattsRestaurant {
	private MenuBuilder menuBuilder;
	public void setBuilder(MenuBuilder menuBuilder) {
		this.menuBuilder = menuBuilder;
	}
	public Menu buildMenu(){
		menuBuilder.buildStarter();
		menuBuilder.buildMainCourse();
		menuBuilder.buildDessert();
		menuBuilder.buildDrink();
		return menuBuilder.build();
	}
}

Dann tritt der Erbauer in Aktion. Im gewählten Beispiel wäre das ein Küchenchef:

public abstract class MenuBuilder {
	Menu menu = new Menu();
	abstract void buildStarter();
	abstract void buildMainCourse();
	abstract void buildDessert();
	abstract void buildDrink();
	Menu build()
{
		return menu;
	}
}

Der konkrete Erbauer, hier also der Koch, erbaut (konstruiert/kocht) die einzelnen Bestandteile des bestellten Menüs. Dazu überschreibt (override) er die vorliegenden „abstrakten“ Menü-Punkte:

public class MenuOfTheDayBuilder extends MenuBuilder {
	@Override
	public void buildStarter() {
		burger.setStarter("Kürbis-Suppe");
	}
	@Override
	public void buildMainCourse() {
		burger.setMainCourse("Gegrilltes Rindfleisch mit Pommes Frites");
	}
	@Override
	public void buildDessert() {
		burger.setDessert("Vanille-Eis");
	}
	@Override
	public void buildDrink() {
		burger.setDrink("Hauswein Rot");
	}
}

Schließlich werden die einzelnen Punkte zusammengefasst ausgeführt und an den Gast ausgeliefert, in der Programmiersprache also „ausgedruckt“:

public class Main {
	public static void main(String[] args) {
		MattsRestaurant mattsRestaurant = new MattsRestaurant();
		menuRestaurant.setBuilder(new MenuOfTheDayBuilderBuilder());
		buildMenu(menuRestaurant);
		menuRestaurant.setBuilder(new SpecialMenuBuilder());
		buildMenu(menuRestaurant);
	}
	private static void buildMenu(MattsRestaurant mattsRestaurant) {
		MenuOfTheDay menu = mattsRestaurant.buildMenu();
		menu.print();
	}
}
Hinweis

Das gewählte Beispiel beruht auf den Codes von Daniel Høyer Jacobsen, der auf seiner Webseite Design Patterns in Java mehrere Entwurfsmuster illustriert vorstellt.