Fluent Interface

Fluent Interface

Fluent Interfaces[1] stellen in der Software-Entwicklung eine Art Programmierschnittstelle dar, die es ermöglicht, beinahe in Satzform Funktionalitäten aufzurufen. Der daraus resultierende Programmcode ist leicht lesbar und macht somit das Verständnis über dessen Intention leicht. Fluent Interfaces können Grammatiken realisieren, die dafür sorgen, dass der Benutzer einer solchen Schnittstelle immer einen gültigen Satz schreibt, also die Schnittstelle richtig verwendet. Es gibt zwei Arten, solche flüssigen Schnittstellen zu realisieren, Method Chaining[2] (Methodenketten) und Nested Functions[3] (Eingebettete Funktionen).

Inhaltsverzeichnis

Grundlagen

Als Begründer von Fluent Interfaces gelten Eric Evans und Martin Fowler. Mit der Beispielimplementierung des Entwurfsmusters Specification[4] brachten diese den Ansatz hervor, neue Objekte mit Hilfe von Methodenketten auf flüssige Weise zu erstellen.

 Specification colorSpec = new ColorSpecification();
 Specification lengthSpec = new LengthSpecification(); 
 if(colorSpec.and(lengthSpec).isSatisfiedBy(obj)) {
     ...
 }

Wie man im oberen Beispiel sieht, wird ganz explizit geschrieben, dass ein Objekt auf beide Bedingungen getestet wird. Ein weiteres Beispiel wäre das flüssige Erstellen eines Datums.

 DateFactory.newDate().year(2009).month(2).day(07);

Im Vergleich zur Verwendung eines Konstruktors sieht man explizit, welche Rolle die einzelnen Werte spielen. Hinzu kommt, dass der Entwickler einer solchen Schnittstelle die Reihenfolge, in der die Methoden aufgerufen werden dürfen, reglementieren kann. Somit können z.B. Methodenaufrufe, die mehrere Parameter erwarten, wesentlich verständlicher, expliziter, gemacht werden.

Gerade in Evans’ Domain-Driven Design spielen Fluent Interfaces eine besondere Rolle, denn sie dienen dazu, spezifische Eigenschaften aus einer Domäne explizit im Programmcode auszudrücken. Fluent Interfaces gehören damit zu den sogenannten Internen Domänenspezifischen Sprachen[5] (in[6] auch als Eingebettete Sprache bezeichnet). Dabei handelt es sich um Domänenspezifische Sprachen, die direkt mit den Mitteln einer Programmiersprache realisiert sind.

Implementierung

Naiv ohne Grammatik

Die Beispielimplementierung von Evans und Fowler für Specifications folgte einem naiven Ansatz. Um die oben gezeigte Methodenkette zu realisieren, genügte es dem Interface Specification einfach, die nötige Methode and() hinzuzufügen.

 public interface Specification {
 
     Specification and(Specification spec);
 
     boolean isSatisfiedBy(Object obj);
 
 }

Mit dem Aufruf der verknüpfenden Methode and() wird also immer eine Specification geliefert, an der man wiederum die Methode and() aufrufen könnte. Jedoch wird durch diesen naiven Ansatz die Implementierung von Typen um Funktionalitäten angereichert, die im Grunde nichts mit dem eigentlich Sinn dessen zu tun haben. Der eigentliche Nachteil ist aber, dass man nicht kontrollieren kann, in welcher Reihenfolge die Methoden aufgerufen werden dürfen.

Mit Grammatik

Häufig spielt die Reihenfolge, in der die Methoden einer Methodenkette aneinander gereiht werden dürfen, eine große Rolle. Das folgende Beispiel zeigt die Verwendung eines Fluent Interfaces, das einem Objekt vom Typ Date einige Tage und Stunden hinzufügt.

Date date = CalendarUtils
        .add(5).days()
        .add(10).hours()
        .to(date);

Würde man wie im naiven Ansatz mit jedem Aufruf einer Methode immer den gleichen Typen zurückliefern, wäre es möglich, den Satz eventuell vorzeitig oder falsch zu beenden. Um die gewünschte Grammatik zu realisieren, muss also mit dem Aufruf einer Methode ein anderer Typ zurückgegeben werden, der die richtigen Folge-Methoden bereithält. Folgendes Beispiel zeigt, dass der Aufruf der Methode newDate() von DateUtils zur Rückgabe eines Mediators führt. Dieser hält dann die Folge-Methode add bereit. Der Aufruf der Methode add wiederum führt ebenfalls zur Rückgabe eines neuen Mediator usw.

 public class DateUtils {
    public static Mediator newDate() { 
        ...
    }
 }
 
 public class Mediator {
     public Mediator2 add(int i) {
         ...
     }
 }
 
 public class Mediator2 {
     public Mediator3 days() {
         ...
     }
 }
 
...
// possible sentence
DateUtils.newDate().add(5).days(). ...

Bernd Schiffer bezeichnet diese Mediatoren auch als Deskriptoren.[7] Mit obigem Beispiel wird also eine Grammatik realisiert, die genau vorgibt, in welcher Reihenfolge die Methoden aufgerufen werden dürfen. Des Weiteren liefert die Methodenkette solange kein Objekt vom Typ Date, bis diese richtig beendet wird. Somit wird man schon durch Kompilierungsfehler und vor Laufzeit einer Anwendung auf eventuelle Fehler aufmerksam gemacht.

Vorteile

Die Verwendung von Fluent Interfaces bietet einige Vorteile, die sowohl die Programmentwicklung erleichtern als auch die Verständlichkeit des Programmcodes fördern.

  • Fluent Interfaces können einem natürlich-sprachlichen Satz ähneln. Das führt dazu, dass zusätzliche Kommentare im Programmcode überflüssig werden.
  • Durch ein satzähnliches Fluent Interface ist es dem Benutzer möglich, klare Erwartungen an den Satzaufbau, also die bereitgestellten Funktionalitäten, zu stellen.
  • Die Autovervollständigung einer Entwicklungsumgebung wie Eclipse hilft dabei, herauszufinden, welche Methoden als Nächstes aufgerufen werden dürfen.
  • Durch Kompilierungsfehler wird man schon vor der Laufzeit auf die falsche Verwendung eines Fluent Interfaces hingewiesen.

Nachteile

Die Realisierung einer Grammatik für Fluent Interface ist sehr umständlich. Das notwendige Netzwerk von Mediatoren wird schnell unübersichtlich. Zudem lässt sich auf dieser Ebene schwer nachvollziehen, welche Satzkonstruktionen möglich sind. Unter[8] ist ein Ansatz zu finden, bei dem versucht wird, dieses Defizit aufzuheben, indem man die Grammatik von Fluent Interfaces in Form von Diagrammen modelliert. Aus einem solchen Modell wird dann der notwendige Code automatisch generiert, sodass es nur noch nötig ist, das Verhalten des Fluent Interfaces zu implementieren.

Die langen Ketten von Methodenaufrufen erschweren das Debuggen, da ein Callstack typischerweise nur die Zeile des Fehlers enthält, nicht aber die Spalte im Source-File. Das gleiche gilt für die Zuordnung von Warnungen aus der statischen Codeanalyse.

Einsatzmöglichkeiten

Fluent Interfaces können für verschiedene Zwecke eingesetzt werden. Im Vordergrund steht dabei immer, explizit zu machen, was in einer Domäne verankert ist.

  • Wrapping von Funktionalitäten
    Wie oben bereits dargestellt, können Fluent Interfaces dazu verwendet werden, bestehende Funktionalitäten verständlicher bereitzustellen.
  • Flüssiger Erbauer
    In[7] wird das Konzept des flüssigen Erbauers gezeigt. Dabei wird das Konzept des Fluent Interfaces auf das Entwurfsmuster Erbauer übertragen.
  • Abbildung fremder Syntax
    Mit Hilfe von Fluent Interfaces können interpretierte Sprachen (wie z.B. SQL, XPath oder HQL), die häufig in Form eines Strings im Programmcode wieder zu finden sind, abgebildet werden.

Weblinks

Einzelnachweise

  1. Fluent Interfaces (Bliki-Eintrag von Martin Fowler)
  2. Method Chaining (Bliki-Eintrag von Martin Fowler)
  3. Nested Functions (Bliki-Eintrag von Martin Fowler)
  4. Specifications
  5. Domain Specific Language (Bliki-Eintrag von Martin Fowler)
  6. Evolving an Embedded Domain-Specific Language in Java
  7. a b Flüssiger Erbauer
  8. Modellgetriebene Realisierung von Fluent Interfaces

Wikimedia Foundation.

Игры ⚽ Поможем решить контрольную работу

Schlagen Sie auch in anderen Wörterbüchern nach:

  • Fluent interface — In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is an object oriented construct that defines a behavior capable of relaying the instruction context of a subsequent call. Generally, the context is *… …   Wikipedia

  • Fluent interface — Текучий интерфейс (англ. fluent interface, название придумано Эриком Эвансом и Мартином Фаулером) способ реализации, в разработке программного обеспечения, объектно ориентированного API, нацеленный на повышение читабельности исходного кода… …   Википедия

  • Fluent — can refer to:* fluency, in linguistics, the ability to communicate quickly. * fluent (mathematics), in mathematics, a continuous function * fluent (artificial intelligence), in artificial intelligence, a condition that varies over time * Fluent,… …   Wikipedia

  • Fluent — Siège de la société …   Wikipédia en Français

  • Multiple frames interface — A Multiple Frames Interface (MFI) is a type of user interface which displays information in a set of frames or panels that can be scrolled vertically on the screen. It is an integrated interface designed to bring together virtually all the… …   Wikipedia

  • Désignation chaînée — Fluent Interface / Interface fluide En génie logiciel, une désignation chaînée ou chaînage de méthodes consiste à agir en une seule instruction sur plusieurs méthodes du même objet, dans un but de plus grande lisibilité. L idée principale est qu… …   Wikipédia en Français

  • Moose (analysis) — Moose Screenshot  …   Wikipedia

  • Ribbon — В этой статье не хватает ссылок на источники информации. Информация должна быть проверяема, иначе она может быть поставлена под сомнение и удалена. Вы можете отредактировать эту стать …   Википедия

  • Design Pattern — Entwurfsmuster (engl. design pattern) sind bewährte Lösungs Schablonen für wiederkehrende Entwurfsprobleme der Softwarearchitektur und Softwareentwicklung. Sie stellen damit eine wiederverwendbare Vorlage zur Problemlösung dar, die in einem… …   Deutsch Wikipedia

  • Design Patterns — Entwurfsmuster (engl. design pattern) sind bewährte Lösungs Schablonen für wiederkehrende Entwurfsprobleme der Softwarearchitektur und Softwareentwicklung. Sie stellen damit eine wiederverwendbare Vorlage zur Problemlösung dar, die in einem… …   Deutsch Wikipedia

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”