Flexibel programmieren mit dem Fluent Interface

Seite 2: Flexibilität gewinnen

Inhaltsverzeichnis

Eine klassische API für diesen Anwendungsfall besteht aus den zwei Klassen Abschnitt und AbschnittUtil. Listing 1 zeigt einen Ausschnitt der Testklasse AbschnittTest. Abschnitte können demnach Werte für Stellen aufnehmen, und man kann diese Werte für eine bestimmte Stelle wiederfinden. Um den Abschnitt zu erzeugen, erfolgt zunächst seine Instanziierung über einen Default-Konstruktor. Per Setter für die Instanzvariable name wird der Abschnittsname gesetzt. Schließlich werden zwei Werte an zwei verschiedene Stellen geschrieben.

Der Test benötigt eigentlich "einen Abschnitt mit Namen abschnittsname mit Wert a an Stelle 1 und mit Wert b an Stelle 2". Tatsächlich aber wurde ihm bislang etwas vorgesetzt, was zusammengefasst und ohne Variablen so aussieht:

Abschnitt abschnitt = new Abschnitt();
abschnitt.setName("abschnittsname");
abschnitt.add(1, "a");
abschnitt.add(2, "b");

Dies liest sich weitaus holpriger als im normalen Sprachgebrauch. Es ist faszinierend, zwei Programmierern dabei zuzuhören, wie sie sich gegenseitig beispielsweise beim Pair Programming Code dieser Art vorlesen. Anstatt so etwas zu sagen wie "Hier benötigen wir einen Abschnitt mit Namen abschnittsname mit Wert a an Stelle 1", was ein grammatikalisch korrekter deutscher Satz wäre, sagen sie etwa "Hier machen wir einen new Abschnitt und setzen danach den abschnittsnamen und dann adden wir noch 1 Komma a".

Ein naiver Ansatz zur Lösung dieses Lesbarkeitsproblems ist die Einführung eines entsprechenden Konstruktors, etwa:

public Abschnitt(String name, Abschnittseintrag eintrag...){
/* Implementierung */}

Hierbei ist ein Abschnittseintrag nur eine Hilfsklasse zur Aufnahme einer Stelle und eines dazugehörigen Wertes. Der Aufruf erfolgt dann so:

Abschnitt abschnitt = 
new Abschnitt("abschnittsname",
new Abschnittseintrag(1, "a"),
new Abschnittseintrag(2, "b"))

Damit ist die Konstruktion eines Abschnitts auf eine Anweisung reduziert, allerdings auf Kosten der Flexibiliät: Für jede anderweitige Konstruktion eines Abschnitts müsste der Konstruktor respektive die Factory-Methode überladen werden, etwa wenn Abschnitte mit IDs, Validatoren, Konvertern, Typen und anderen für die Konstruktion nötigen Teilen gebaut würden. Da wäre die Übersicht bald nicht mehr gegeben, und ein armer Programmierer mag sich bald fragen, welchen der vielen Konstruktoren er aufrufen muss. Nicht gut.

Erforderlich ist zudem, dass der Programmierer weiß, ob das gerade gebaute Objekt konsistent ist. Eine kurze Definition für die Konsistenz eines Abschnitts besagt: "Ein Abschnitt muss immer einen Namen haben. Er darf keine bis beliebig viele Stelle-Wert-Paare haben." Diese Information steht jedoch nicht zum Konstruktionszeitpunkt – also beim Programmieren – zur Verfügung, sondern zeigt sich gegebenenfalls erst zur Laufzeit durch schwer nachvollziehbare Fehlermeldungen. Das heißt, Entwickler haben es mit einer unlesbaren, unflexiblen, unübersichtlichen und inkonsistenten – einer fest(gefahren)en – API zu tun.