Informatik

Schnittstellen

Nur Leistungskurs. Diese Lektion gehört zu den zusätzlichen Anforderungen des Leistungskurses. Im Grundkurs kannst du sie überspringen.

Das Problem

Eine abstrakte Klasse löst ein Problem: Sie erzwingt, dass alle Unterklassen eine bestimmte Methode anbieten. Aber sie hat eine harte Grenze.

In deinem Spiel gibt es Klassen, die sich bewegen können: Spieler, Gegner, Geschoss. Sie alle erben bereits von Sprite.

Du möchtest zusätzlich erzwingen, dass jede von ihnen eine Methode beschleunige(double pFaktor) anbietet.

Warum kannst du dafür keine abstrakte Klasse Beweglich einsetzen?

Auflösung

Weil eine Klasse in Java nur von einer Oberklasse erben kann. Spieler erbt schon von Sprite – für Beweglich ist kein Platz mehr.

Man könnte Beweglich zwischen Sprite und Spieler schieben. Das geht aber nur, wenn wirklich alle beweglichen Dinge auch Sprites sind. Sobald ein bewegliches Objekt kein Sprite ist – etwa eine Kamerafahrt –, bricht der Entwurf.

Die Lösung

Eine Schnittstelle (englisch interface) legt fest, welche Methoden eine Klasse anbieten muss – ohne etwas über deren Umsetzung zu sagen und ohne in die Vererbungshierarchie einzugreifen.

Eine Klasse kann von einer Klasse erben, aber beliebig viele Schnittstellen implementieren.

  • interface Bezahlbar deklariert nur Signaturen. Alle Methoden sind automatisch öffentlich und abstrakt – man schreibt public abstract nicht dazu.
  • class Angestellter extends Mitarbeiter implements Bezahlbarerst die Oberklasse, dann die Schnittstellen.
  • Eine Klasse darf mehrere Schnittstellen implementieren: implements Bezahlbar, Vergleichbar, Speicherbar.
  • Eine Schnittstelle ist ein Typ. Deshalb geht Bezahlbar[] posten – obwohl Angestellter und Stromrechnung überhaupt nichts miteinander zu tun haben.

Im Diagramm schreibt man <<interface>> über den Namen und verbindet die implementierende Klasse mit einem gestrichelten Pfeil mit leerem Dreieck.

classDiagram
    class Bezahlbar {
        <<interface>>
        +double betrag()
        +String bezeichnung()
    }
    class Mitarbeiter {
        <<abstract>>
        #String name
        +double berechneGehalt()*
    }
    class Angestellter {
        -int stufe
        +double berechneGehalt()
        +double betrag()
        +String bezeichnung()
    }
    class Stromrechnung {
        -double monatsbetrag
        +double betrag()
        +String bezeichnung()
    }
    Mitarbeiter <|-- Angestellter
    Bezahlbar <|.. Angestellter
    Bezahlbar <|.. Stromrechnung

Abstrakte Klasse oder Schnittstelle?

abstrakte Klasse Schnittstelle
Attribute ja nein (nur Konstanten)
Konstruktor ja nein
Methodenrümpfe ja nein
wie viele pro Klasse? genau eine beliebig viele
Beziehung ist ein kann etwas

Faustregel: Teilen die Klassen gemeinsamen Zustand und gemeinsames Verhalten? Dann abstrakte Klasse. Teilen sie nur eine Fähigkeit, sind aber sonst grundverschieden? Dann Schnittstelle.

Ein Angestellter ist ein Mitarbeiter. Eine Stromrechnung ist kein Mitarbeiter – aber beide können bezahlt werden.

Entscheide jeweils: abstrakte Klasse oder Schnittstelle? Begründe.

a) Fahrzeug für Auto, Fahrrad, LKW

b) Speicherbar für alles, was sich in eine Datei schreiben lässt

c) Konto für Girokonto und Sparkonto

d) Vergleichbar für alles, was sich sortieren lässt

Auflösung

a) Abstrakte Klasse. Alle Fahrzeuge teilen Zustand (Geschwindigkeit, Position) und Verhalten.

b) Schnittstelle. Ein Bild, ein Spielstand und ein Adressbuch sind grundverschiedene Dinge – gemeinsam ist ihnen nur die Fähigkeit.

c) Abstrakte Klasse. Beide haben einen Kontostand und einen Besitzer.

d) Schnittstelle. Zahlen, Wörter, Personen und Termine haben nichts gemeinsam außer der Vergleichbarkeit.

Aufgabe: Vergleichbar

Diese Schnittstelle brauchst du im Kapitel über Bäume wieder – dort heißt sie in der NRW-Klassenbibliothek ComparableContent.

Setze die Schnittstelle und zwei implementierende Klassen so um, dass alle Tests grün werden.

Die Sortiermethode in Sortierer soll beliebige vergleichbare Objekte sortieren können – ohne zu wissen, worum es sich handelt.

Tipp 1: Der Vergleich in Buch

Der Parameter ist vom Typ Vergleichbar – die Schnittstelle kennt aber keine Seitenzahl. Du musst ihn also erst in ein Buch umwandeln:

Buch anderes = (Buch) pAnderes;
return seiten > anderes.getSeiten();

Das ist eine der wenigen Stellen, an denen eine Typumwandlung nach unten sachlich richtig ist: Ein Buch kann sich sinnvollerweise nur mit einem anderen Buch vergleichen.

Tipp 2: Der Sortierer

Es ist genau das Sortieren durch Auswählen aus der Einführungsphase. Nur der Vergleich sieht anders aus: statt pWerte[j] < pWerte[kleinstesIndex] heißt es jetzt

pWerte[kleinstesIndex].istGroesserAls(pWerte[j])

Und der Merker hat den Typ Vergleichbar statt int.

Tipp 3: Warum funktioniert das für Bücher und Personen gleichzeitig?

Weil Sortierer gar nicht wissen muss, was es sortiert. Es weiß nur: Jedes Element kann sich mit einem anderen vergleichen. Wie es das tut, ist Sache der jeweiligen Klasse.

Genau dafür sind Schnittstellen da.

Lösung. Erfrage das Passwort bei deiner Lehrkraft.

Zusatzaufgabe

In der Einführungsphase gab es in der Zusatzaufgabe zur Stadt die Idee, alle Objekte zwischen Tag und Nacht umzuschalten – und in der letzten Lektion die abstrakte Klasse Stadtobjekt als Lösung.

a) Baue es stattdessen mit einer Schnittstelle Umschaltbar. Was ändert sich?

b) Welche Lösung ist hier besser? Begründe mit der Faustregel „ist ein“ gegen „kann etwas“.

c) Was, wenn manche Stadtobjekte umschaltbar sein sollen und andere nicht – etwa ein Zaun, der nachts genauso aussieht? Welche Lösung kommt damit besser zurecht?


Selbsttest

Schnittstellen

Teilbare URL erstellen

Abschnitte auswählen