In den letzten Monaten hat sich eine interessante Diskussion entwickelt über ein design pattern, das vom “Erfinder” Ralf Westphal “Event-Based Components” (EBC) getauft wurde. In diesem Blogpost stellt er sie erstmals vor. Da Ralf aus dem .NET-Umfeld kommt, findet die gesamte Diskussion zurzeit in der .NET-Community statt und konzentriert sich auf eine Umsetzung in C#. Da ich auch in Java programmiere, habe ich eine Implementierung des Konzeptes umgesetzt in Java. Das möchte ich in diesem Blog nach und nach vorstellen. Da die Diskussion noch recht neu ist, hat sich noch kein fester Wortschatz für EBC etabliert. Es kann daher sein, dass einzelne Artikel über EBC eine andere Begrifflichkeit benutzen als ich hier. Das ändert aber nichts am Prinzip.
Grundgedanken
Der Grundgedanke der EBCs ist die vollständige Loslösung von anderen Komponenten. Diese Entkopplung ist auch in aktuellen OOP Diskussionen ein wichtiger Punkt, wie nicht zuletzt das Inversion of Control (IoC) pattern und die Vielzahl der Dependency Injection (DI) Frameworks, die zurzeit um die Gunst der Programmierer buhlen, zeigen. Dennoch sind bei IoC Abhängigkeiten vorhanden, und DI ist nur ein Mittel, die Befriedigung der Abhängigkeiten zu vereinfachen. IoC zielt auf die Entkopplung von der Implementierung, nicht von der Schnittstelle. Damit werden zweifellos einige wichtige Ziele erreicht: Implementierungen lassen sich problemlos austauschen, ggf. sogar zur Laufzeit, die Objekte können leicht getestet werden, weil hinter den abhängigen Schnittstellen test doubles versteckt werden können, die leicht zu erstellen sind. Diese Komponenten auf Basis von IoC nennt Ralf, und ich möchte das übernehmen, IBC – Interface Based Components.
Wenn man Component mal mit Baustein übersetzt und dann an Bausteine in der physischen Welt denkt, dann landet man z.B. bei elektronischen Bauteilen wie Widerständern, bei Ziegelsteinen oder vielleicht auch bei Legosteinen. Bei diesen gibt es einen eklatanten Unterschied zu IBCs: Die physischen Bausteine sind unabhängig von anderen Bausteinen. Natürlich gibt es eine Vereinbarung, wie verschiedene Bausteine zusammengesetzt werden, aber keiner der Bausteine ist von bestimmten anderen abhängig. Lediglich die Art, wie sie zusammengesetzt werden, bestimmt das Ergebnis. Um beim Legostein zu bleiben: es ist dem Stein völlig egal, ob er auf die Bodenplatte gesetzt wird oder den Abschlussstein einer Lego-Kathedrale bildet. Solange einige Noppen der richtigen Größe vorhanden sind, passt er.
Ganz neu sind die Gedanken übrigens nicht. Das ganze Konzept weist auffällige Ähnlichkeiten zum Flow Based Programming auf, das J. Paul Morrison bereits 1994 beschrieben hat und dessen Buch zu dem Thema gerade in einer neuen Auflage erschienen ist.
Nachrichten
Die Vereinbarung, wie EBCs zusammengesetzt werden, sind Ereignisse oder Nachrichten. Eine EBC kann Nachrichten empfangen und Nachrichten senden. Woher diese kommen und wohin sie gehen, ist der Komponente egal. Lediglich die Nutzlast, also das in der Nachricht enthaltenen Datum, muss passen, damit die Komponente ihre Aufgabe erfüllen kann. Das macht eine EBC ebenso simpel wie elegant. Es ist nichts weiter als:

Eine Komponente zum Einlesen einer Adresse. Die Symbolik ist ein Vorschlag von mir. Der offene Halbkreis ist ein Eingangspin, der volle Kreis ein Ausgangspin. Das am Pin anliegende Datum steht in spitzen Klammern, entsprechend der Generic-Syntax in Java oder C#.
Ein- und Ausgabedatum können natürlich unterschiedlich sein, sowohl vom Inhalt her als auch vom Typ. Ein Grundprinzip ist allerdings, dass auf jedem Ein- oder Ausgang nur ein Datenobjekt übergeben wird. Mehr dazu später. Mehrere Komponenten werden aneinander gehängt, wobei der Ausgang einer Komponente an den Eingang einer anderen Komponente gehängt wird. In der Diskussion hat sich der Begriff “Pin” ausgeprägt, womit das Bild der Elektrotechnik wieder aufgenommen wird.
Obwohl EBC als design pattern keine direkte Implmentierung impliziert, so finde ich es doch hilfreich, auch für die Umsetzung ein Muster zur Hand zu haben. Das soll nicht heißen, dass die hier vorgestellten Muster der Weisheit letzter Schluss sind. Es mögen für spezielle EBC spezielle Umsetzungen sinnvoll sein, oder ganz generell andere Varianten geben.
In C# können Pins sehr direkt umgesetzt werden. Ein Ausgangspin ist ein event:
public event Action<Adresse> Result;
Ein Eingangspin ist eine einfache Methode mit einem Parameter und ohne Rückgabewert. Stattdessen wird das Ergebnis über einen Ausgangspin, also ein event, weitergereicht.
public void Start(Schluessel schluessel) {
// erstelle Adresse
Result(adresse);
}
Es gibt also Eingangspins und Ausgangspins und es wird ein Eingangspin mit einem Ausgangspin verdrahtet:

Verbindung von Komponenten
Die Verdrahtung geschieht in C# entsprechend einfach:
AdresseBestimmen.Result += AdresseEinlesen.Start;
Da Java weder Events noch Funktionsreferenzen (delegates) als elementare Sprachbestandteile hat, kommt man nicht umhin, für die Pins Typen zu definieren. Das hat in meinen Augen aber auch den Vorteil, dass Pins als solche sofort zu erkennen sind, während sie in C# als “normale” Elemente in ihrer speziellen Funktion nicht so leicht zu erkennen sind. Pins können klassisch als Interface definiert werden, wobei sie einen genrischen Typen erhalten, der das zwischen den Pins zu übertragende Datum darstellt. Der Ausgabepin enthält eine Methode zum Verdrahten mit einem Eingabepin. Und beide haben je eine Methode für die Kommunikation.
public interface InPin<T> {
void receive(T message);
}
public interface OutPin<T> {
void wire(InPin<T> in);
void send (T message);
}
Verdrahtet wird dann mit
und gesendet mit
Bauteile und Platinen
Komponenten können auf jeder gewünschten Abstraktionsebene entworfen werden. So ist “Adresse einlesen” sicherlich aus mehreren kleineren Komponenten zusammengesetzt, die einzelne Aufgaben wahrnehmen. “Adresse einlesen” könnte so aussehen:

Eine Komponente kann aus anderen zusammen gesetzt sein
Der Ein- und Ausgangspin bleiben natürlich unverändert. Im Detail sieht man aber, dass der Eingangspin zu einer Komponente führt, die die Datenbankabfrage erstellt. Diese Abfrage wird an eine Komponente weitergereicht, die Abfragen ausführt und daraus Resultsets erstellt. Eine dritte Komponente erhält das Resultset und baut daraus die fertige Adresse. Eine Komponente kann also entweder atomar oder zusammengesetzt sein. Von außen sieht man ihr das nicht an. Eine atomare Komponente möchte ich als Bauteil bezeichnen, eine zusammengesetzte als Platine. Eine Platine hat keine andere Funktion, als Bauteile oder andere Platinen miteinander zu verdrahten (und sie, sofern nicht von außen mitgegeben, zu erstellen). Ein Platine hat somit also keinerlei fachlichen Programmcode. Dementsprechend einfach ist sie aufgebaut. Wenn wir das linke Beispiel in etwas Code übersetzen wollen, käme in etwa das dabei heraus:
public class AdresseEinlesen {
private AbfrageErstellen abfrageErstellen = new AbfrageErstellen();
private DatenbankabfrageAusfuehren abfrageAusfuehren = new DatenbankabfrageAusfuehren();
private AdressobjektErstellen adresseErstellen = new AdressobjektErstellen();
public AdresseEinlesen() {
abfrageErstellen.Result().wire(abfrageAusfuehren.Start());
abfrageAusfuehren.Result().wire(adresseErstellen.Start());
}
public InPin<Schluessel> Start() {
return abfrageErstellen.Start();
}
public OutPin<Adresse> Result() {
return adresseErstellen.Result();
}
}
Es kann das Diagramm also fast 1:1 in Programmcode übersetzt werden. Jede Verbindung innerhalb der Platine entspricht einem Aufrufe von wire(), jeder Pin nach außen entspricht einer Methode, die den Pin bereit stellt. Dabei muss die Platine keine eigenen Pin-Variablen bereit halten – sie kann einfach die “losen Enden” der Bauteile weiterreichen.
Diese Übersetzbarkeit von Diagramm in Code schreit eigentlich nach einem grafischen Designer, nicht?
Ausblick
Das waren einige Grundgedanken zu EBCs. Ich werde in den nächsten Blog-Posts die Umsetzung in den Vordergrund stellen, weil die Theorie von Ralf in senem o.g. Blog besser verständlich beschrieben wird, als ich es je könnte. Ich werde dabei einige weitere interessante Vorteile der EBCs vorstellen, z.B. die elegante Umsetzung von Aspekten der AOP, oder die einfache Testbarkeit im Vergleich zu IBCs.
Quelltexte
Die Quelltexte zum Blog – immer in einer zumindest kompilierbaren Form – finden sich bei Github, für diesen Post ist es der Commit 913ad01. Noch ohne wirklichen Inhalt…