Java: Builder Pattern mit Subclassing

Grundprinzip (eine Klasse)

Eine Herausforderung, der wohl jeder objektorientierte Programmierer einmal gegenübersteht, ist diejenige von elend langen Parameterlisten in Konstruktoren. Insbesondere wenn Vererbung im Spiel ist akkumulieren sich die nötigen Parameter bei jeder Spezialisierung mehr und es wird fast unmöglich, bei der Initialisierung den Durchblick zu behalten, welches Argument jetzt für welchen Parameter gedacht ist, insbesondere, wenn mehrere Parameter denselben Datentyp aufweisen. Zudem wird es zunehmends aufwendiger, bei allfälligen optionalen Parametern für alle Fälle einen Konstruktor mit passenden Parametern bereitzustellen.

 

Eine Lösung für Java bietet das sogenannte Builder-Pattern. Bei diesem erhält die Klasse mit den zu vielen Parametern eine geschachtelte ('nested') Klasse "Builder", welche dieselben Felder wie die Hauptklasse hat. Im Builder-Konstruktor müssen alle Parameter, welche nicht optional sind übergeben werden. Für jedes optionale Feld hat die Klasse eine Setter-Methode. Diese Setter-Methoden geben jeweils ihre eigene Klasseninstanz von Builder zurück, womit es möglich wird, diese Methoden zu verketten. Eine weitere Methode namens build() der Builder-Klasse ruft dann den Konstruktor der Hauptklasse auf, welche als Parameter eine Builder-Instanz nimmt, und dessen Attributswerte ausliest.

 

Das Builder Pattern wurde massgeblich geprägt von Joshua Bloch, und wird hier im Detail erklärt: http://www.drdobbs.com/jvm/creating-and-destroying-java-objects-par/208403883?pgno=2

Builder Pattern mit Subclassing

Wird das Builder Pattern auf eine alleinstehende Klasse angewandt, ist die Implementierung ziemlich einfach. Deutlich komplexer wird die Angelegenheit jedoch, wenn das Builder Pattern in Klassen, welche voneinander erben eingebaut werden soll. Lösungen gibt es verschiedene, jede mit ihren eigenen Vor- und Nachteilen. Für das Projekt, an welchem ich zurzeit arbeite, habe ich die Lösung von David Moles adaptiert und erweitert. Erläuterungen zu David Moles' Lösung finden sich hier: https://chrononaut.org/2013/03/19/subclassing-with-blochs-builder-pattern-revised/ 

Beispiel mit optionalen Parametern mit Default-Werten

Im folgenden ein Beispiel, wie dieses Builder-Pattern angewendet werden kann. Der Hauptunterschied, bzw. um was die obige Lösung ergänzt wurde ist, wie Default-Werte für diejenigen Parameter gesetzt werden, welche vom Benutzer nicht angegeben wurden.

Zum Projekt

Das Projekt, für welches hier das Builder Pattern verwendet wurde, ist ein Game, welches dem Klassiker "Zork" von 1980 nachempfunden wurde. Wenn "under the hood" das Projekt auf viel modernere Technologien zurückgreift, sieht es für den Benutzer vom Stil her genau so aus, wie das originale Zork von vor 38 Jahren.

 

Das Beispiel hier demonstriert zwei Klassen, und zwar die Item-Klasse, welches ein Objekt repräsentiert, welches sind in Räumen oder dem Inventar des Spielers befinden kann, und mit welchem interagiert werden kann. Von der Klasse Item erbt unter anderem die Klasse ItemContainer, deren Instanzen einerseits selbst Items sind, andererseits aber weitere Items in sich beinhalten können.

Code

Im folgenden die Klassen "Item" und "ItemContainer". Da es hier lediglich um die Instanziierung dieser Klassen geht, sind alle Methoden, welche damit nichts zu tun haben der Einfachheit halber weggelassen worden.

Klasse Item

(Klick ins Bild zum Vergrössern)

Klasse ItemContainer

(Klick ins Bild zum Vergrössern)