Wozu sind Interfaces beim programmieren nützlich?

7 Antworten

Das hat den Vorteil, dass du eine Katze oder einen Hund auch einfach als Tier speichern kannst. Du kannst also zum Beispiel folgendes machen:

Tier meinTier = new Katze();
meinTier.laufen();

Die Variable kann auch für ein beliebiges anderes Tier genutzt werden:

meinTier = new Hund();
meinTier.laufen();

Besonders nützlich wird das, wenn du zum Beispiel eine Liste an Tieren haben willst, diese aber nicht auf eine bestimmte Tierart beschränken willst:

List<Tier> tiere = new ArrayList<Tier>();
tiere.add(new Katze());
tiere.add(new Hund());
tiere.add(new Baer());
tiere.add(new Affe());

Auf jedem beliebigen Element der Liste kann nun laufen() aufgerufen werden, da dank des Interfaces sichergegangen werden kann, dass jedes Tier laufen kann.

tiere.get(2).laufen(); // Bär läuft
tiere.get(0).laufen(); // Katze läuft

Im professionellen Umfeld werden Interfaces zum Beispiel auch genutzt, um Schnittstellen zu definieren und verschiedene Implementationen dafür anzubieten.

Ein praktisches Beispiel hierfür wäre zum Beispiel eine Datenquelle (bzw. Datenbank). Du machst dann ein Interface, welche ein paar Methoden definiert, um mit der Datenquelle zu interagieren. getNameOfUser(), getPostById() und so weiter und so fort.

Dann schreibst du eine Klasse, welche dieses Interface implementiert. Diese Klasse ist dann zum Beispiel dafür zuständig, um mit einer MySQL Datenbank zu kommunizieren und enthält Code, welcher abhängig zu dieser Datenbank ist.

Wenn du nun von deinem Programm aus auf die Datenquelle zugreifen willst, machst du das durch das Interface. Nun zum Vorteil der ganzen Geschichte: Ein Nutzer deiner Applikation will lieber PostgreSQL statt MySQL nutzen. Du brauchst nun also nur eine neue Klasse machen, die ebenfalls das Interface nutzt und dort dann mit der PostgreSQL Datenbank kommuniziert. Im Code musst du dann nur an einer einzigen (oder nur sehr wenigen) Stellen kurz was austauschen und schon kannst du eine andere Datenquelle verwenden.

Hättest du das nicht so gemacht, sondern deine Interaktionen mit der Datenquelle direkt irgendwo im Programm gemacht, müsstest du das mühsam einzeln abändern gehen.

Woher ich das weiß:Berufserfahrung – Informatiker Applikationsentwicklung

Hey,

nutzt man das Interface, hat man den Vorteil, bspw. eine List<Tier> zu machen, in welcher somit Hunde UND Katzen sein können (da ja beide das Interface implementen), man kann sie also gruppieren. Somit kann auf JEDES Tier in der Liste direkt die laufen Methode aufgerufen werden.

Mfg Jannick (L1nd)

Woher ich das weiß:eigene Erfahrung

In Interfaces definiert man in der Regel eher, welche Funktionen eine Klasse unterstützt. Typische Interfaces in Java sind z.B. Comparable oder Runnable. Wenn du jetzt eine Klasse hast, die das Interface Runnable implementiert, dann muss die Klasse auch alle Methoden bereitstellen, die im Interface Runnable definiert sind (in dem Fall nur die Methode run()). Dadurch kannst du dann wieder Methoden bauen, die mit Objekten aus unterschiedlichen Klassen umgehen können, die nichts gemeinsam haben müssen, außer dass sie halt z.B. eine Methode namens "run" haben, die man aufrufen kann.

Dein Beispiel mit dem Interface "Tier" ist also eher ein schlechtes Beispiel. Wenn, dann würde man z.B. ein Interface namens TreeClimber machen, was dann z.B. von Katzen, Bären, Affen und Ameisen implementiert wird. Die Klassen müssen dann eine Methode namens climbTree() haben, womit sie Bäume hochklettern können. Die Klasse Tier wäre in dem Fall nur eine abstrakte Klasse, von der die anderen Klassen erben.

In einem Wort: Abstraktion

Diese ganzen simplen Vererbungs-Beispiele mit Tier und Katze oder Fahrzeug und Auto sind zwar möglich, aber meistens macht man genau das eben nicht.
Das ist ein häufiger Fehler, der die Vorteile von Interfaces zunichte machen kann.

Ein sehr gutes Beispiel von Minecraft: Inventare

In Minecraft haben sehr viele sehr verschiedene Blöcke ein Inventar, das mit Vererbung zu lösen, würde zu einer sehr aufwendigen und hinderlichen Vererbungshierarchie führen, die das Projekt über Kurz oder Lang unwartbar machen könnte.

Viel besser:
Man implementiert für die einzelnen Blöcke jeweils passend zugeschnittene Klassen oder Vererbungshierarchien und sie alle implementieren ein Interface, dass Methoden zum Lesen und Bearbeiten vom Inventar definiert.

So vermeidest Du die gefährliche und unnötig komplexe Vererbung, dennoch kann jede Methode, die irgendetwas mit einem Inventar tun soll, damit arbeiten. Und noch besser: Du kannst nachträglich etwas völlig neues entwickeln, ohne bestehenden Code bearbeiten, solange Du das Interface implementierst, funktionieren die genannten Methoden.

Gut nun haben wir einen Hund und eine Katze, die jeweils laufen können. Und übergeben dieses Tier einer anderen Klasse bzw. Methode, die das Tier laufen lassen soll.

Möchtest du nun eine Methode pro Tier machen? Immerhin musst du im Parameter angeben was du übergibst. Mit deinem Beispiel übergibst du entweder eine Katze oder ein Hund. Und für jedes Tier, was du hinzufügst, musst du diesen Code auch neu anpassen, kompilieren usw.

Stell es dir mal weg von Software vor. Interfaces bzw. Schnittstellen haben wir an vielen Stellen. Zum Beispiel ganz klassisches bei Hardware. Stell dir mal vor jeder würde hier sein eigenes Süppchen kochen. Jedes mal, wenn du eine neue Maus oder Tastatur kaufst, muss jemand vorbei kommen und an deinem USB-Port rumlöten, weil der nicht weiß, dass er irgendwann mal genau diese Maus bekommt und wie die funktioniert. Wäre nicht so praktisch oder?

Ergo gibt es eine Schnittstelle dazwischen und es ist definiert wie diese funktioniert. Der Computer weiß nur, wie er dieses Schnittstelle verwenden kann und die Maus, die muss ihre Magie wieder in diese Schnittstelle übersetzen. Klar du hast noch Treiber dahinter usw.

Alternativ schaffst du eine gemeinsame Basis, denn der Klasse, die das laufen auf deinem Tier ausführen will, der ist komplett egal, ob es ein Hund oder eine Katze ist und wenn da morgen ein Pinguin hinzu kommt, ist das auch egal. Sie weiß nur, sie kriegt ein Tier und das Tier kann laufen.

Damit entkoppelst du den Code, musst Code der sich eigentlich nicht von seiner Funktion ändert nicht anpassen, ggf. Fehler einbauen, ihn neu kompilieren, ihn neu Übertragen etc. pp.

Sprich deine Klasse, die mit diese Tieren arbeitet, ist erweiterbar und das ohne sie zu ändern. Einfach indem du weiter unten neue Tiere hinzufügst. Sehr wichtig sind solche Abhängigkeiten z.B. auch bei Plugins für Spiele und Software.

Davon ab von Interfaces erbt man nicht, man implementiert sie oder benutzt sie. Ich weiß, nur Begrifflichkeiten.

Auch ist Tier natürlich ungünstig, denn laufen ist keine Eigenschaft von Tieren. Hunde und Katzen sind ggf. Tiere aber nicht alle Tiere können laufen. Andere schwimmen z.B. Ein Fisch ist definitiv ein Tier, trotzdem kann er nicht laufen. Und auch sind es nicht nur Fische die schwimmen können.

Ein Tier ist vom Namen her eher sowas wie eine Abstrakte Klasse. Hier wären aber diese Methoden falsch.

Du hättest also eher ein LaufenInterface oder ein ILaufen.

Woher ich das weiß:Berufserfahrung – Softwareentwickler/Projektleiter seit 2012