Ich frage nicht nach den Unterschieden zwischen diesen beiden, sondern warum Interfaces häufiger bevorzugt werden als abstrakte Klassen.
Das offensichtlichste "Manko" von abstrakten Klassen ist, dass Vererbungstypen nur von einer einzigen abstrakten Klasse erben können.
Wenn es um Schnittstellen geht, können Sie mehrere Schnittstellen implementieren.
Wenn Sie also Ihre Typen so entwerfen, dass sie mehrere Verträge implementieren müssen, sind Schnittstellen die einzige Option.
Also, zumindest in der C # -Welt, in Verbindung mit den SOLID Prinzipien kann die Neigung zu Schnittstellen erklären.
Ich werde Devil's Advocate hier spielen ...
Ein Vorteil von ABCs gegenüber Interfaces ist, dass Sie Methoden zu einem ABC hinzufügen können, ohne alle abgeleiteten Klassen zu unterbrechen. Wenn Sie einer Schnittstelle eine Methode hinzufügen, brechen Sie jede einzelne Klasse, die diese Schnittstelle implementiert.
Microsoft empfiehlt, Klassen über Schnittstellen zu favorisieren Aus diesem Grund.
Auch ein ABC kann gegebenenfalls eine Standardimplementierung für seine Methoden bereitstellen.
Außerdem kann ein ABC Typen (z. B. enums) und schreibgeschützte Konstanten definieren, während dies bei einer Schnittstelle nicht möglich ist.
Es ist wirklich eine sehr belastete Frage. Beide haben ihren jeweiligen Nutzen in verschiedenen Situationen.
Abstrakte Klassen
Eine abstrakte Klasse wird verwendet, wenn es eine gemeinsame Funktionalität gibt, die zwischen den Unterklassen geteilt wird, aber die Oberklasse selbst wird niemals existieren. Zum Beispiel wird eine Klasse Person
niemals existieren. Allerdings wird eine Klasse Woman
. Anstatt alle Methoden in Woman
, in Man
, Boy
und Girl
zu wiederholen, heben wir sie einfach auf die Superklasse auf, so dass sie alle Zugriff auf diese Funktionalität haben und die Methoden überschreiben können, die sie verwenden möchte anders arbeiten.
Schnittstellen
Schnittstellen werden verwendet, wenn eine Anforderung besteht. Die Art, wie ich sie ansehe, ist wie ein Vertrag. Die Vereinbarung ist, dass jede Klasse, die das Interface implementiert, Code für eine bestimmte Anzahl von Methoden bereitstellen muss.
Zum Beispiel können eine Klasse Rock
und eine Klasse Ball
geworfen werden. Anstelle der Methode, einen Ball zu werfen, jedes auswählbare Objekt zu berücksichtigen, wenn jedes Objekt das ThrowingItem
Interface implementiert (ich wollte das Wort Throwable
aus offensichtlichen Gründen nicht verwenden), dann die Methode kann einfach ein Objekt vom Typ ThrowingItem
akzeptieren und weiß, dass die vereinbarten Methoden da sind.
Dies ermöglicht eine lose Kopplung zwischen der Methode throw
und den Klassen, die sie verwenden, da die gesamte Kommunikation über die Schnittstelle erfolgt.
Wie Sie sehen können, werden die zwei verschiedenen Arten in ziemlich unterschiedlichen Situationen verwendet, und Vergleiche sind wirklich wie Äpfel und Orangen zu vergleichen.
Als Faustregel verwenden wir Schnittstellen, wenn wir bei einer zumindest teilweisen Implementierung nichts über die Implementierungs- und Abstraktionsklassen sagen.
Hier ist meine Faustregel, mit der ich am meisten übereinstimme:
Sobald Sie zur Abstraktion übergehen, können Sie über diesen Hinweis entscheiden, welcher Typ verwendet werden soll: Sie können nicht von mehreren abstrakten Klassen erben. Daher sollten Sie sich wirklich entscheiden zwischen einer abstrakten Klasse oder einer Schnittstelle IMO, wenn Sie eine Implementierung benötigen oder nicht (wenn nicht, dann benutze einfach eine Schnittstelle, um später das Mehrfachüberlagerungs-Potential zu vermeiden)
Wenn Sie einen Typ haben, der entweder als Interface oder als abstrakte Klasse entworfen werden kann, warum sollten Sie die abstrakte Klasse wählen?
In diesem Sinne verwenden wir die abstrakte Klasse nur, wenn einige Funktionen in der Schnittstelle nicht möglich sind:
angeben. obwohl eine Schnittstelle Unterklassen bitten könnte, den Zustand zu implementieren, könnte es einfacher sein, eine abstrakte Oberklasse zu verwenden, um den Zustand zu halten.
Beschränkungszugriff auf protected
. während alle Dinge in der Schnittstelle public
statische Methoden. (Beachten Sie, dass die Schnittstelle in Java 8 wahrscheinlich statische Methoden haben kann)
konkrete Methoden mit Implementierungen. (Beachten Sie, dass Interface-Methoden in Java 8 defualt implizit haben können)
fügen Sie konkretere Methoden hinzu, ohne die Unterklassen zu brechen. (Beachten Sie, dass wir in Java 8 mehr Methoden zu einer vorhandenen Schnittstelle hinzufügen können, wenn die Methoden Standardimpls haben)