Logo Wissenstransfer Gerhard at CichnaDotCom

>> Wissensdatenbank / Objektorientiertes Programmieren

Programmierschnittstellen mit Interfaces

Typische Szenarien für Programmierschnittstellen

Bereits seit 1995 proklamiert die sogenannte "Gang of Four" (eine Gruppe von vier Autoren, die viel zitierte Literatur zum Thema Softwaretechnik verfasst hat) den Einsatz von Interfaces. Es sei ein besserer Programmierstil gegen eine Schnittstelle zu programmieren, als gegen eine Implementierung. Und es gibt tatsächlich zahlreiche Szenarien, in denen der Einsatz dieses Konzepts sinnvoll erscheint. Denn er sorgt für eine klare Trennung zwischen der Spezifikation und der Implementierung. Das heißt, es kann getrennt voneinander festgelegt werden, was bestimmte Klassen oder ganze Pakete können sollen (Spezifikation) und wie diese Funktionalität technisch umgesetzt wird (Implementierung).

Eine solche Trennung bietet zwei Vorteile: Zum einen ermöglicht es eine flexiblere Software-Architektur, da die Implementierung bei Bedarf ausgetauscht werden kann, ohne dass dadurch ein großer Anpassungsaufwand entsteht. Als Beispiel hierfür lässt sich die Druck-Funktion in der Textverarbeitung anführen: Die Schnittstelle für einen Druckertreiber ist klar definiert und bei allen Druckertreiber-Herstellern bekannt. Ein Benutzer kann sich beliebige Treiber installieren und dann bei Bedarf den geeigneten Drucker auswählen - sei es ein PDF-Drucker oder ein echter Drucker.
Flexible Software-Architektur

Der zweite Vorteil der Trennung von Spezifikation und Implementierung liegt darin, dass sie die Wiederverwendung von Klassen oder Paketen erhöht. Eine Klasse, die eine bestimmte Schnittstelle anbietet (implementiert), kann überall dort eingesetzt werden, wo eine solche Funktionalität benötigt wird. Das Programm, in das die Klasse eingebaut wird, muss hierzu nicht angepasst werden. Am Beispiel der Druckertreiber bedeutet das, dass ein Hersteller nicht für jeden PC oder Laptop beziehungsweise deren modellabhängige Ausstattung einen eigenen Druckertreiber programmieren muss.
Wiederverwendung durch einheitliche Schnittstellen

Tipp
Mit der Einführung von Interfaces steht zudem ein weiteres Instrument zur Verfügung, um sich das Konzept der Polymorphie nutzbar zu machen. Polymorphie wurde bis jetzt am Beispiel der Vererbung gezeigt. Dort wurde gezeigt, wie die Methode einer Oberklasse von Unterklassen unterschiedlich neu implementiert wurde. Wenn man alle Klassen aus der Vererbungshierarchie in eine gemeinsame Liste speichert und die Methode der Oberklasse aufruft, wird jeweils die passendste Implementierung von der Laufzeitumgebung ausgewählt (dynamisches Binden). Mithilfe von Interfaces kann die Einschränkung aufgehoben werden, dass sich solche Klassen in einer gemeinsamen Vererbungshierarchie befinden müssen. Entscheidend ist nun nur noch, dass sie ein gemeinsames Interface implementieren. Interfaces eignen sich also als noch mächtigeres Instrument für Polymorphie.

Beispiel-Szenario für den Einsatz von Interfaces:
Beispiel austauschbare Kundenspeicher

Interfaces als Programmierschnittstellen in Java

Schnittstellen werden in Java mit dem Schlüsselwort interface definiert. Die Syntax erinnert sehr an die einer Klasse, mit dem Unterschied, dass alle Methoden abstrakt sind. Das heißt, die Methoden bestehen lediglich aus der Signatur und haben somit keinen durch geschweifte Klammern eingeschlossenen Rumpf. Auf diese Weise können Sie spezifizieren, was eine implementierende Klasse können muss, ohne das "Wie?" vorwegzunehmen. Bei der Definition von Schnittstellen ist zu beachten, dass sie grundsätzlich zustandslos sein müssen. Es ist daher bis auf Konstanten nicht erlaubt, Attribute zu definieren.
Implementierung einer Schnittstelle

Mithilfe des Schlüsselwortes implements kann eine Klasse anzeigen, welche Schnittstelle(n) sie realisiert. Damit verpflichtet sie sich, für jede Methode dieser Schnittstelle(n) eine Implementierung anzubieten.

Auch in der UML ähnelt die Notation von Schnittstellen der von Klassen. Um sie zu unterscheiden, verwendet man das Stereotyp <<interface>>. Mit einer use-Assoziation, dargestellt durch einen gestrichelten Pfeil mit offener Spitze und Stereotyp <<use>>, kann gekennzeichnet werden, dass ein Klasse eine Schnittstelle verwendet. Das heißt, die Klasse ruft mindestens eine Methode der Schnittstelle auf.
UML-Notation eines Interfaces

Die implementierende Klasse zeigt, ähnlich zur Vererbungs-Notation, mit einer geschlossenen Pfeilspitze auf die Schnittstelle. Im Gegensatz zur Vererbung wird der Pfeil aber gestrichelt dargestellt.

Das Interface definiert Methoden, die unabhängig von der Implementierung benötigt werden.
Beispiel Implementierung Interface

Weil die benötigten Methoden zur Speicherung von Kundendaten nun in einer Schnittstelle definiert sind, können sie ohne großen Aufwand beliebig ausgetauscht werden (Flexibilität). Umgekehrt kann die Implementierung zur Speicherung von Kundendaten prinzipiell an jeder weiteren Programmstelle eingesetzt werden, an der ein solches Interface benötigt wird (Wiederverwendbarkeit).

Interfaces können auch von anderen Interfaces erben. Auf diese Weise können Gemeinsamkeiten von Schnittstellen zusammengefasst und je nach Verwendungszweck ohne großen Wartungsaufwand erweitert werden. Bezogen auf Interfaces unterstützt Java außerdem das Konzept der Mehrfachvererbung. Das heißt, im Gegensatz zu Klassen können Interfaces sogar von mehr als einem Interface erben. Trotzdem wird mit extends das gleiche Schlüsselwort verwendet.
Interfaces Mehrfachvererbung in UML
Implementierung einer Interface-Mehrfachvererbung

Die Definition von Interfaces erinnert sehr an abstrakte Klassen. In der Tat gibt es einige Parallelen: Abstrakte Klassen sind ebenfalls in der Lage, mithilfe abstrakter Methoden Klassen-übergreifende Funktionalitäten festzulegen. Im Gegensatz zu abstrakten Klassen spielt bei Interfaces allerdings die Vererbungshierarchie keine Rolle. Das heißt, auch "unverwandte" Klassen können einem gleichen Interface zugeordnet werden und eine Klasse kann mehr als ein Interface implementieren. Hinzu kommt, dass es bei Interfaces im Gegensatz zu abstrakten Klassen verboten ist, implementierte und abstrakte Methoden zu vermischen. Ebenso wird durch das Verbot Attribute zu definieren verhindert, zustandsbehaftete Interfaces zu programmieren.