Wikipedia · einfach zusammengefasst · Stand
Schnittstelle (Objektorientierung)
Eine Schnittstelle oder ein Interface (englisch interface oder protocol) definiert in der objektorientierten Programmierung, welche Methoden in den …
Inhalt5 Abschnitte
Grundidee und Zweck
Eine Schnittstelle, auch Interface oder protocol, legt in der objektorientierten Programmierung fest, welche Methoden Klassen und andere Typen besitzen müssen. Sie definiert die Methodennamen und deren Signatur, also die Parametertypen und den Rückgabetyp.
Neben dieser syntaktischen Festlegung kann eine Schnittstelle einen Kontrakt enthalten. Dieser beschreibt die Bedeutung (Semantik) der Methoden durch Vorbedingungen und Nachbedingungen. Häufig wird der Kontrakt nur informell in der Dokumentation oder einer externen Spezifikation festgelegt. Für formale Spezifikationen stehen beispielsweise die OCL oder – in Sprachen wie Eiffel – direkte syntaktische Möglichkeiten zur Verfügung.
Eine Schnittstelle garantiert, dass eine Klasse bestimmte Methoden bereitstellt. Objekte, die dieselbe Schnittstelle besitzen, können deshalb gleich behandelt werden. Diese Fähigkeit wird Polymorphie genannt. Schnittstellen sind außerdem nicht an einen strengen Klassenbaum gebunden: In Sprachen ohne Mehrfachvererbung, etwa Java, können sie Kompatibilitäten zwischen Klassen herstellen, die nicht voneinander erben. Als vollständiger Ersatz für Mehrfachvererbung eignen sie sich jedoch nur eingeschränkt, da sie normalerweise Methoden und Parameter, nicht aber direkt geerbte Funktionalität festlegen.
Deklaration und besondere Eigenschaften
In vielen Sprachen werden Schnittstellen ausdrücklich mit dem Schlüsselwort interface deklariert. Programmiersprachen mit Mehrfachvererbung, etwa C++, können Schnittstellen auch wie gewöhnliche Klassen behandeln; dabei spricht man häufig von abstrakten Klassen. Für Middleware-Systeme wie CORBA oder DCOM wird teilweise eine eigene Schnittstellenbeschreibungssprache (IDL) verwendet. Objektbasierte Sprachen ohne strenge Typisierung besitzen meist keine Schnittstellen.
In Java können Schnittstellen durch beliebig viele Basisschnittstellen erweitert werden. Dafür wird, analog zur Klassenableitung, das Schlüsselwort extends verwendet. Schnittstellen können außerdem generisch sein.
In einigen Sprachen, darunter Java und PHP, dürfen in einer Schnittstellendefinition Konstanten deklariert werden. Diese stehen anschließend allen implementierenden Klassen zur Verfügung.
Java-Schnittstellen können keine Konstruktoren enthalten und nicht direkt instanziiert werden. Ein Ausdruck wie new Konto() ist daher unzulässig. In Java sind nicht ausdrücklich qualifizierte Methoden einer Schnittstelle automatisch public. Variablen sind automatisch public, static und final.
Seit Java SE 8 können Schnittstellen außerdem Default-Methoden enthalten. Das sind vordefinierte Implementierungen, die von implementierenden Klassen übernommen werden können. Anders als bei abstrakten Methoden ist eine Überschreibung nicht verpflichtend.
Beispiel in C#
Die Schnittstelle Face deklariert die Methoden Move(...), Turn(...), Scale(...), GetArea(), SetColor(...) und GetColor(). Die Klasse Polygon implementiert Face, was mit Polygon : Face angegeben wird. Deshalb muss Polygon sämtliche Methoden mit den festgelegten Parametertypen und Rückgabetypen bereitstellen; die Implementierungen besitzen den Zugriffsmodifikator public.
Im Beispiel verschiebt Move die Punkte eines Polygons um x und y. Turn dreht sie um einen Winkel in Grad um den Punkt (x, y); dazu wird der Winkel mit angleInRadians = angleInDegrees * (Math.PI / 180) in Bogenmaß umgerechnet und die Drehmatrix der Ebene verwendet. Scale skaliert die Punktkoordinaten mit factor. GetArea berechnet die Fläche aus den Polygonpunkten und gibt Math.Abs(area / 2.0) zurück. Diese Berechnung verwendet die Gaußsche Trapezformel. SetColor setzt die Farbe, GetColor gibt sie zurück.
Beispiel und Regeln in Java
Eine Schnittstelle Konto kann beispielsweise die Methode getKontostand() festlegen. Klassen wie SparKonto, GiroKonto und DepotKonto, die Konto implementieren, müssen diese Methode bereitstellen. Die Deklaration int getKontostand(); ist eine abstrakte Signatur-Definition und implizit public. SparKonto implementiert die Methode beispielsweise, indem es seinen privaten kontostand zurückgibt.
Implementiert eine Klasse zwei Schnittstellen mit derselben Methode, genügt eine einzige Überschreibung, die bei polymorpher Verwendung über beide Schnittstellen genutzt wird. Voraussetzung sind dieselbe Signatur – Bezeichner und Parameterliste – und derselbe Rückgabetyp.
Eine Klasse muss eine Schnittstelle nicht selbst explizit implementieren, wenn sie die Anforderungen durch eine geerbte Methode erfüllt. Im Beispiel erbt B von A, wobei A die Methode foo() besitzt, und deklariert zusätzlich implements I. Ein Objekt new B() kann dann über den Typ I verwendet werden; der Aufruf i.foo() führt die geerbte Methode aus.
Auf Default-Methoden kann man sich mit MyInterface.super beziehen. Diese Schreibweise verweist ausdrücklich auf den Namensraum der Schnittstelle und ist erforderlich, wenn die ursprüngliche Variante einer überschriebenen Default-Methode aufgerufen werden soll. Bei einem Konflikt zwischen einer konkreten Basisklasse und einer gleichnamigen Default-Methode hat die Methode der Basisklasse Vorrang. Gleichartige Default-Methoden mit identischer Signatur aus mehreren Schnittstellen verursachen dagegen einen Compilerfehler, sofern die Klasse den Konflikt nicht durch eine eigene Überschreibung auflöst.
Java erlaubt außerdem anonyme innere Klassen, die eine Schnittstelle direkt innerhalb einer Methode implementieren. Eine Methode kann beispielsweise ein Konto zurückgeben, dessen getKontostand() den Wert 0 liefert.
Eine Schnittstelle mit genau einer abstrakten Methode heißt funktional. Funktionale Schnittstellen bilden die Grundlage für Lambda-Ausdrücke und Methodenreferenzen. Der Compiler bestimmt aus dem Kontext, welche funktionale Schnittstelle und welche zu überschreibende Methode gemeint sind. Die Annotation @FunctionalInterface überprüft diese Eigenschaft ausdrücklich.
Namenskonventionen
In manchen Programmiersprachen werden Schnittstellen durch Präfixe oder Suffixe kenntlich gemacht. Häufig steht ein I am Anfang oder IF beziehungsweise Interface am Ende. Die Schnittstelle Konto könnte dann IKonto, KontoIF oder KontoInterface heißen.
Dafür spricht, dass der Typ am Namen sofort erkennbar ist und implementierende Klassen einen einfacheren Namen erhalten können. Dagegen wird eingewandt, dass Verwender eines Objekts grundsätzlich nur dessen Schnittstelle, also seine öffentlichen Methoden, beachten sollten. Außerdem können Implementierungen als wesentliches Element der Programmierung betrachtet werden; dann wäre es sinnvoller, deren Namen durch Präfixe oder Suffixe zu ergänzen. Da Schnittstellen besonders bei mehreren Implementierungen nützlich sind, werden die Implementierungen ohnehin häufig näher bezeichnet.
Schnittstellen, die allgemeine Fähigkeiten oder Zustände ausdrücken, tragen – besonders in der Java-Standardbibliothek – oft adjektivische Namen wie Serializable oder Comparable<T>.