<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://mletkin.net/index.php?action=history&amp;feed=atom&amp;title=Builder_mit_Interfaces_%28Draft%29</id>
	<title>Builder mit Interfaces (Draft) - Versionsgeschichte</title>
	<link rel="self" type="application/atom+xml" href="https://mletkin.net/index.php?action=history&amp;feed=atom&amp;title=Builder_mit_Interfaces_%28Draft%29"/>
	<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Builder_mit_Interfaces_(Draft)&amp;action=history"/>
	<updated>2026-05-06T13:43:34Z</updated>
	<subtitle>Versionsgeschichte dieser Seite in MimiPedia</subtitle>
	<generator>MediaWiki 1.39.4</generator>
	<entry>
		<id>https://mletkin.net/index.php?title=Builder_mit_Interfaces_(Draft)&amp;diff=30&amp;oldid=prev</id>
		<title>Ullrich: Die Seite wurde neu angelegt: „== Reihenfolge der Methoden-Ausführung == Normalerweise sollte die Reihenfolge in der die Modifier-Methoden aufgerufen werden keine Rolle spielen. Sofern das…“</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Builder_mit_Interfaces_(Draft)&amp;diff=30&amp;oldid=prev"/>
		<updated>2021-04-12T17:30:27Z</updated>

		<summary type="html">&lt;p&gt;Die Seite wurde neu angelegt: „== Reihenfolge der Methoden-Ausführung == Normalerweise sollte die Reihenfolge in der die Modifier-Methoden aufgerufen werden keine Rolle spielen. Sofern das…“&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;== Reihenfolge der Methoden-Ausführung ==&lt;br /&gt;
Normalerweise sollte die Reihenfolge in der die Modifier-Methoden aufgerufen werden keine Rolle spielen.&lt;br /&gt;
Sofern das eine Frage der Lesbarkeit ist -- so sollte zuerst die Straße und dann die Hausnummer angegeben werden --&lt;br /&gt;
läßt sich das in der Reegel organisatorisch -- also per Handbuch -- steuern lassen, falls es sich nicht (wie bei der Hausnummer)&lt;br /&gt;
von selbst regelt.&lt;br /&gt;
&lt;br /&gt;
Man kann das Problem zur Laufzeit entweder mit Prüfungen und Exceptions behandeln und dabei das Risiko eingehen damit&lt;br /&gt;
in die Produktion zu gehen wenn die Tests lückenhaft sind. Falls ein Modifier auf die Erfassung der Daten durch einen anderen&lt;br /&gt;
Modifier angewiesen ist, kann man das Problem mit Buffering und verzögerter Auswertung umgehen (-&amp;gt; Beispiel??).&lt;br /&gt;
&lt;br /&gt;
Wäre aber nicht eine Lösung wünschenswert, die Probleme zur Compile-Zeit erkennt und es damit unmöglich macht, daß diese&lt;br /&gt;
in die Produktion gelangen? Im Prinzip ja, leider gehen solche Maßnahmen in der Regel mit erhöhtem Aufwand einher; man tut&lt;br /&gt;
also gut daran genau zu überlegen wann sich der Aufwand lohnt.&lt;br /&gt;
&lt;br /&gt;
== Interfaces, Interfaces ==&lt;br /&gt;
Eine relativ komfortable Lösung bieten Interfaces, sor allem deshalb, weil man sie &amp;#039;&amp;#039;nachträglich&amp;#039;&amp;#039; hinzufügen kann.&lt;br /&gt;
Wir nehmen einfach das obige Beispiel und bauen eine einfachen Builder:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class AdressBuilder {&lt;br /&gt;
    Adresse adr = new Adresse();&lt;br /&gt;
&lt;br /&gt;
    public static AdressBuilder neu() {&lt;br /&gt;
        return new AdressBuilder();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public AdressBuilder withStrasse(String strasse) {&lt;br /&gt;
        adr.setStrasse(strasse)&lt;br /&gt;
        return this;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public AdressBuilder withHausnummer(int nr) {&lt;br /&gt;
        adr.setHausnummer(nr);&lt;br /&gt;
        return this;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public Adresse get() {&lt;br /&gt;
        return adr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Bei der Verwendung des Builders können wir eine Reihe von unerwünschten Dinge treiben:&lt;br /&gt;
* die Modifier in beliebiger Reihenfolge aufrufen&lt;br /&gt;
* den Aufruf eines Modifiers auslassen&lt;br /&gt;
* einen Modifier mehrfach aufrufen&lt;br /&gt;
Jede der drei Situationen läßt sich zur Compile-Zeit verhindern, indem wir drei Interfaces einführen&lt;br /&gt;
und über diese die Reihenfolge steuern. Zur Verdeutlichung -- und zur vereinfachung -- numerieren&lt;br /&gt;
wir die Interfaces einfach durch. Wir beginnen mit dem ersten Interface für die Methode {{java|withStrasse}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public interface First {&lt;br /&gt;
    Second strasse(String strasse);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Das Interface {{java|First}} -- wie das in den Builder eingebaut wird, sehen wir nachher -- erlaubt ausschließlich die Angabe der Straße.&lt;br /&gt;
Anschließend geht&amp;#039;s weiter mit dem Interface {{java|Second}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public interface Second {&lt;br /&gt;
    Finish hausnummer(int nummer);&lt;br /&gt;
}&lt;br /&gt;
}} &lt;br /&gt;
das -- ausschließlich -- die Angabe der Hausnummer erlaubt. Danach könnten in dieser Vorgehensweise weitere Interfaces folgen,&lt;br /&gt;
für unser Beispiel ist die Reise vorbei und wir enden mit dem Interface {{java|Finish}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public interface Finish {&lt;br /&gt;
    Adresse get();&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
das nur noch den Aufruf der Generator-Methode erlaubt. Wir halten schonmal fest: Für die Festlegung der &lt;br /&gt;
Reihenfolge von &amp;#039;&amp;#039;n&amp;#039;&amp;#039; Methoden benötigen wir &amp;#039;&amp;#039;n + 1&amp;#039;&amp;#039; (winzige) Interfaces. Bauen wir die Interfaces nun in unseren Builder ein:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class AdressBuilder implements First, Second, Finish {&lt;br /&gt;
    Adresse adr = new Adresse();&lt;br /&gt;
&lt;br /&gt;
    public static First neu() {&lt;br /&gt;
        return new AdressBuilder();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public AdressBuilder withStrasse(String strasse) {&lt;br /&gt;
        adr.setStrasse(strasse)&lt;br /&gt;
        return this;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public AdressBuilder withHausnummer(int nr) {&lt;br /&gt;
        adr.setHausnummer(nr);&lt;br /&gt;
        return this;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public Adresse get() {&lt;br /&gt;
        return adr;&lt;br /&gt;
    }&lt;br /&gt;
}}}&lt;br /&gt;
Wir haben am Builder tatsächlich nur zwei Änderungen vorgenommen:&lt;br /&gt;
&lt;br /&gt;
Zunächst weisen wir den Builder n, die drei Interfaces zu implementieren.&lt;br /&gt;
In der Folge erhalten die Methoden die Annotation {{java|@Override}}.&lt;br /&gt;
&lt;br /&gt;
Die einzige Stelle an der eines der Interfaces -- das erste -- eingetragen werden muß ist an der&lt;br /&gt;
Creation-Methode. Wir haben hierfür eine statische Methoden {{java|neu}} definiert, denn aus offensichtlichem Grunde&lt;br /&gt;
funktioniert die Interface-Lösung nicht, wenn Konstruktoren verwendet werden. Dadurch wird erreicht,&lt;br /&gt;
daß zu Anfang nur die Methode {{java|withStrasse}} zur Verfügung steht, der Anfang der Kette.&lt;br /&gt;
&lt;br /&gt;
Wie die Kette funktionert läßt sich am einfachsten in der IDE ausprobieren. Man tippt die Folge&lt;br /&gt;
{{java| code=&lt;br /&gt;
AdressBuilder.neu().strasse(&amp;quot;&amp;quot;).hausnummer(0).get();&lt;br /&gt;
}}&lt;br /&gt;
ein und schaut sich nach jedem Punkt die möglichen anwendbaren Methoden an. Neben den unvermeidlichen&lt;br /&gt;
{{java|Object}}-Methoden steht immer nur eine Methode des {{java|AdressBuilder}} zur Auswahl.&lt;br /&gt;
&lt;br /&gt;
=== Optionale Aufrufe ===&lt;br /&gt;
Bis hierher ist der Aufruf &amp;#039;&amp;#039;jeder&amp;#039;&amp;#039; der Builder-Methoden zwingend erforderlich.&lt;br /&gt;
Nehmen wir an, die Angabe der Hausnummer sei optional und die entsprechende Methode soll übersprungen werden können.&lt;br /&gt;
Dazu müssen wir dem entsprechenden Interface ({{java|Second}}) die zusätzliche Möglichkeit geben die Methode {{java|get}} aufzurufen.&lt;br /&gt;
Das können wir so machen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public interface First{&lt;br /&gt;
    Finish hausnummer(int nummer);&lt;br /&gt;
    Adresse get();&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Damit implementiert die Methode {{java|get}} im {{java|AdressBuilder}} nun zwei Interfaces.&lt;br /&gt;
Nachteil dieser Lösung ist, daß die beiden Interfaces synchron gehalten werden müssen. Das iat&lt;br /&gt;
normalerweise kein Problem, weil sich der Typ des Builder-Generats in der Regel nicht ändert.&lt;br /&gt;
Aber es dupliziert eine Zeile und für jede optionale Modifier-Methode müssen wir die Zeile wiederholen.&lt;br /&gt;
&lt;br /&gt;
Hier also die Alternative. Dafür modifizieren wir das Interface {{java|First}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public interface First {&lt;br /&gt;
    &amp;lt;T extends Second &amp;amp; Finish&amp;gt; T strasse(String strasse);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Statt im Interface {{java|Second}} anzugeben daß das Interface übersprungen werden kann,&lt;br /&gt;
geben wir nun an der Methode {{java|withStrasse}} an, welche Interfaces im Anschluß angewandt werden können.&lt;br /&gt;
Ein feiner aber wichtiger Unterschied im Design.&lt;br /&gt;
&lt;br /&gt;
Java bietet uns hier durch die Forderung der Typ {{java|T}} müsse &amp;#039;&amp;#039;zwei&amp;#039;&amp;#039; Interfaces implementieren&lt;br /&gt;
eine Alternative zur nicht vorhandenen Mehrfachvererbung. Die Implementierung der Methode muß ein Objekt&lt;br /&gt;
im Ergebnis liefern, das &amp;#039;&amp;#039;beide&amp;#039;&amp;#039; Interfaces implementiert. {{java|AdressBuilder}} tut das:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class AdressBuilder implements First, Second, Finish {&lt;br /&gt;
...&lt;br /&gt;
    @Override&lt;br /&gt;
    public AdressBuilder withStrasse(String strasse) {&lt;br /&gt;
        adr.setStrasse(strasse)&lt;br /&gt;
        return this;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Der Compiler sieht dabei allerdings ein Problem und warnt uns davor, daß hier eine ungeprüfter Typ-Konversion&lt;br /&gt;
stattfindet obwohl das offensichtlich kein Problem darstellt...&lt;br /&gt;
&lt;br /&gt;
Den Effekt kann man in der IDE wieder sehr schön nachvollziehen.&lt;br /&gt;
&lt;br /&gt;
== Alternativen ==&lt;br /&gt;
Anstelle der Straße möchten wir gerne ein Postfach angeben können.&lt;br /&gt;
In diesem Falle sind weder Straße noch Hausnummer sinnvoll. Dazu erweitern wir zunächst den Builder um&lt;br /&gt;
eine Modifier-Methode:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@Override&lt;br /&gt;
public AdressBuilder withPostfach(int postfach) {&lt;br /&gt;
   adr.setPostfach(postfach);&lt;br /&gt;
   return this;&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Die IDE wird dann freundlicherweise das Interface {{java|First}} für uns erweitern und wir müssen nur die Signatur anpassen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Finish withPostfach(int postfach);&lt;br /&gt;
}}&lt;br /&gt;
Da hinter der Hausnummer nichts mehr kommt, gehen wir hier gleich zur Generator-Methode -- sprich zu Interface {{java|Finish}} über.&lt;br /&gt;
&lt;br /&gt;
Die Verweendung eines Interface anstelle der Generator-Methode verschafft uns hier noch einen weiteren Vorteil.&lt;br /&gt;
Wenn wir nun eine weitere Modifier-Methode -- etwa für den Ort -- mit einem weiteren Interface einführen,&lt;br /&gt;
schiebt sich eine weitere Ebene zwischen {{java|First}} und die Generator-Methode mit einem weiteren Interface das {{java|Third}} heißen möge.&lt;br /&gt;
Dafür brauchen wir dann nur den Ergebnis-Typ der {{java|withPostfach}}-Methode auf {{java|Third}} zu ändern. &lt;br /&gt;
Wir gewinnen also Einheitlichkeit und damit Änderungsfreundlichkeit.&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Abschließend stellt sich die Frage, was für Strukturen wir auf diese Weise modellieren können?&lt;br /&gt;
Ohne den formalen Beweis zu erbringen liegt die Vermutung nahe, daß jede Methoden-Kette die sich als endlicher&lt;br /&gt;
Automat darstellen läßt mit Hilfe der Interface-Methode modellieren läßt. Die Knoten des Automaten bilden die Interfaces&lt;br /&gt;
und die Kanten die Modifier-Methoden.&lt;br /&gt;
=== was nicht geht ===&lt;br /&gt;
Was uns zu der Frage nach den Grenzen der Methode führt. In der Gruppe Straße/Postfach haben wir eine Alternative programmiert.&lt;br /&gt;
Wollten wir in der Gruppe A/B zusätzlich die Variante &amp;quot;A und B&amp;quot; zulassen, müssen wir das über ein separates Interface machen.&lt;br /&gt;
Andernfalls müssen wir entweder die Variante &amp;quot;weder A noch B&amp;quot; oder die Mehrfach-Anwendung von A bzw. B zulassen.&lt;br /&gt;
&lt;br /&gt;
Abgrenzung zu kontextfreien Sprachen... Folgen... Klammerungs-Äquivalent geht nicht&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
</feed>