Schnittstelle interface |
|
Wie wir oben gesehen haben, kann man Objekte mittels Composition aus anderen Objekten zusammensetzen, meist ein Haupt-Objekt mit Unter-Objekten. In der Praxis will das Haupt-Objekt dann während des Programmlaufs beim Unter-Objekt bestimmte Methoden aufrufen, dazu ist das Unter-Objekt da. Wenn ich also die Klassen-Definition für ein Haupt-Objekt programmiere, und das Unter-Objekt noch nicht kenne, muss ich mich darauf verlassen, dass jedes zukünftige/potentielle Unter-Objekt bestimmte Methoden ausführen wird. Ich brauche einen Mechanismus, der jedes potentielle Unter-Objekt zwingt, bestimmte Methoden zu können. Dieser Mechanismus, der das Vorhandensein bestimmter Methoden erzwingt, heisst interface oder Schnittstelle.
Eine Schnittstelle (ein interface) legt fest, welche Methoden vorhanden sein sollen, ohne die Methoden inhaltlich festzulegen. Dazu braucht man eine Klasse: Was diese Methoden konkret tun sollen, entscheidet die Klasse, durch die das interface implementiert wird. Eine Klasse, die ein interface implementiert, wird vom Java-Compiler gezwungen alle Methoden des interface zu implementieren.
Wenn also mehrere Klassen ein und dasselbe interface implementieren, dann besitzen sie alle die Methoden aus dem interface, und können diese bei Bedarf unterschiedlich implementieren.
Die Leistung des interface ist: alle implementierenden Klassen haben
Beispiel: Ein Haupt-Objekt soll geometrische Figuren als Unter-Objekte aufnehmen und bei diesen dann den Flächeninhalt und den Umfang abfragen, beispielsweise weil das Haupt-Objekt für die Produktion den Materialbedarf berechnen muss. Die Unter-Objekte sind aber vorher nicht bekannt. Man definiert also ein passendes Interface mit Namen Geom , mit dem das Vorhandensein der gewünschten Methoden garantiert wird:
Eine Schnittstelle/ein interface wird wie eine Klasse in einer java-Datei definiert und diese Datei wird kompiliert wie eine Klassen-Datei. Die Definition der Schnittstelle beginnt mit dem Schlüsselwort interface:
public interface Geom
{
public double flaeche();
public double umfang();
}
Die Klassen, welche diese Schnittstelle implementieren, werden gekennzeichnet durch das Schlüsselwort implements:
public class Ellipse extends Kreis implements Geom
{
//Def. der Klasse Ellipse
}
Damit hat diese Klasse die Verpflichtung, die Methoden des interface zu definieren, nämlich flaeche() und umfang(). Wenn die Klassen für die Unter-Objekte die Schnittstelle implementieren, dann sind die Programmierer der Klassen für die Unter-Objekte gezwungen, die Methoden mit genau der Signatur zu schreiben wie in der Schnittstelle definiert.
public class Kreis implements Geom
{
private double radius;
public void setzeRadius( double rad ){
radius = rad ;
}
public double flaeche(){
return Math.PI * radius * radius;
}
public double leseRadius(){
return radius;
}
public double umfang(){
return 2*Math.PI*radius;
}
}
public class Rechteck implements Geom
{
private double lang, breit;
public void setLang( double lang ){
this.lang = lang;
}
public void setBreit( double b ){
breit = b;
}
public double getLang(){
return lang;
}
public double getBreit(){
return breit;
}
public double flaeche(){
return lang*breit;
}
public double umfang(){
return 2*(lang+breit);
}
Nun folgt die Klasse, die der Nutzniesser des ganzen Aufwandes mit den Interfaces ist: Ein Haupt-Objekte der Klasse MaterialBedarf soll mit seinen Methoden flaechenBedarf() und gesamtUmfang() nur solche Unter-Objekte als Parameter akzeptieren, die das Interface Geom implementieren, weil bei diesen die Garantie besteht, dass die Methoden flaeche() und umfang() aufgerufen werden können:
public class MaterialBedarf
{
public double flaechenBedarf( Geom teil ){
return teil.flaeche();
}
public double gesamtUmfang( Geom teil ){
return teil.umfang();
}
}
interfacedemo (Das package wurde hier aus Gründen der Platzersparnis weggelassen, auch das Interface gehört zu einem Package.)
Geom, Kreis, Viereck, MaterialBedarf und kompiliere aus dem Verzeichnis darüber.
MaterialBedarf die main-Funktion und überzeuge sich, dass sowohl Kreis als auch Viereck-Objekte korrekt verarbeitet werden, z.B
public static void main( String [] args ){
//Konstruktor-Aufrufe für Kreise und Rechtecke etc
MaterialBedarf mb1 = new MaterialBedarf();
System.out.println( "Kreis-Umfang: " + mb1.gesamtUmfang( kreis1 ));
System.out.println( "Rechteck-Flaeche: " + mb1.flaechenBedarf( rechteck1 ));
//...
}
Man nehme eine der Interface-Methoden aus einer implementierenden Klasse heraus und betrachte die Fehlermeldung, die der Kompiler dann produziert.
Ein weiterer Gesichtspunkt von interfaces: In grossen Software-Projekten erstellt der Projektleiter die Interfaces und zwingt seine Programmierer dadurch, die Methoden genauso zu schreiben wie bestellt: Mit Schnittstellen kann man eine einheitliche Signatur gleicher Methoden in grossen Projekten sicherstellen.
Ebenso akzeptieren viele vorgefertigte Java-Klassen für die Gestaltung grafischer Oberflächen nur solche Unter-Objekte, die ganz bestimmte Interfaces implementieren.