Bei den bisherigen Antworten lag der Schwerpunkt auf der Programmierung auf einer Abstraktion, um die Erweiterbarkeit und die lose Kopplung zu gewährleisten. Dies sind zwar sehr wichtige Punkte, Lesbarkeit ist ebenso wichtig. Die Lesbarkeit ermöglicht es anderen (und Ihrem zukünftigen Ich), den Code mit minimalem Aufwand zu verstehen. Aus diesem Grund nutzt die Lesbarkeit Abstraktionen.
Eine Abstraktion ist per Definition einfacher als ihre Implementierung. Eine Abstraktion lässt Details weg, um das Wesentliche oder den Zweck einer Sache zu vermitteln, aber nicht mehr. Da Abstraktionen einfacher sind, kann ich im Vergleich zu Implementierungen viel mehr von ihnen auf einmal in meinem Kopf unterbringen.
Als Programmierer (in jeder Sprache) habe ich eine allgemeine Vorstellung von einer List
die ganze Zeit in meinem Kopf. Vor allem eine List
erlaubt den zufälligen Zugriff, die Duplizierung von Elementen und die Aufrechterhaltung der Ordnung. Wenn ich eine Erklärung wie diese sehe: List myList = new ArrayList()
Glaube ich, cool ist dies ein List
das in der (grundlegenden) Weise verwendet wird, die ich verstehe; und ich muss nicht weiter darüber nachdenken.
Andererseits trage ich nicht die spezifischen Implementierungsdetails von ArrayList
in meinem Kopf. Wenn ich also sehe, ArrayList myList = new ArrayList()
. denke ich, Oh-oh diese ArrayList
muss in einer Weise verwendet werden, die nicht unter die List
Schnittstelle. Jetzt muss ich alle Verwendungszwecke dieser Schnittstelle aufspüren ArrayList
um zu verstehen, warum, denn sonst kann ich diesen Code nicht vollständig verstehen. Noch verwirrender wird es, wenn ich feststelle, dass 100 % der Verwendungen dieses ArrayList
faire entsprechen dem List
Schnittstelle. Dann frage ich mich... gab es einen Code, der sich auf ArrayList
Implementierungsdetails, die gelöscht wurden? War der Programmierer, der sie instanziiert hat, einfach nur inkompetent? Ist diese Anwendung zur Laufzeit auf irgendeine Weise an diese spezielle Implementierung gebunden? Auf eine Weise, die ich nicht verstehe?
Ich bin jetzt verwirrt und unsicher über diese Anwendung, und alles, worüber wir reden, ist eine einfache List
. Was wäre, wenn es sich um ein komplexes Geschäftsobjekt handeln würde, das seine Schnittstelle ignoriert? Dann reicht mein Wissen über die Geschäftsdomäne nicht aus, um den Zweck des Codes zu verstehen.
Selbst wenn ich also eine List
streng innerhalb einer private
Methode (nichts, was andere Anwendungen kaputt machen würde, wenn es geändert würde, und ich könnte jede Verwendung in meiner IDE leicht finden/ersetzen), ist es immer noch von Vorteil für die Lesbarkeit, auf eine Abstraktion zu programmieren. Denn Abstraktionen sind einfacher als Implementierungsdetails. Man könnte sagen, dass die Programmierung nach Abstraktionen eine Möglichkeit ist, sich an die KISS Prinzip.
4 Stimmen
Wenn Sie sich daran erinnern können und Ihr Programm optimal sein soll, können Sie kurz vor der Kompilierung die Schnittstellendeklaration gegen die tatsächliche Implementierung austauschen. Die Verwendung einer Schnittstelle fügt eine Ebene der Indirektion hinzu, die zu Leistungseinbußen führt. Verteilen Sie Ihren auf Schnittstellen programmierten Code jedoch...
25 Stimmen
@Ande Turner: Das ist ein schlechter Ratschlag. 1). "Ihr Programm muss optimal sein" ist kein guter Grund für das Auslagern von Schnittstellen! Dann sagen Sie: "Verteilen Sie Ihren programmierten Code trotzdem auf Schnittstellen..." Sie raten also, dass Sie bei Anforderung (1) dann suboptimalen Code veröffentlichen?!?
87 Stimmen
Die meisten der Antworten hier sind nicht ganz richtig. Es bedeutet nicht oder impliziert nicht einmal "das Schlüsselwort interface verwenden". Eine Schnittstelle ist eine Spezifikation, wie etwas zu verwenden ist - gleichbedeutend mit dem Vertrag (schlagen Sie es nach). Getrennt davon ist die Implementierung, die besagt, wie der Vertrag erfüllt wird. Programmieren Sie nur gegen die Garantien der Methode/des Typs, so dass, wenn die Methode/der Typ auf eine Weise geändert wird, die immer noch dem Vertrag entspricht, der Code, der sie verwendet, nicht kaputt geht.
2 Stimmen
@apollodude217 das ist eigentlich die beste Antwort auf der ganzen Seite. Zumindest für die Frage im Titel, da es hier mindestens 3 ganz unterschiedliche Fragen gibt...
7 Stimmen
Das grundsätzliche Problem bei Fragen wie dieser ist, dass sie davon ausgehen, dass "Programmieren für eine Schnittstelle" bedeutet, "alles in eine abstrakte Schnittstelle verpacken", was albern ist, wenn man bedenkt, dass der Begriff das Konzept der abstrakten Schnittstellen im Java-Stil vorwegnimmt.
0 Stimmen
Dies geschieht meist mit COM. Man behandelt ein Objekt, ohne die Klasse zu kennen, sondern nur die Schnittstelle, die es unterstützt.
0 Stimmen
Es ist nur ein schickes Wort für Rückruf . Das ist alles, was es bedeutet. Es bedeutet nur, dass Sie etwas tun (z. B. "Informationen aus dem Netz holen" oder "eine Berechnung durchführen"). Diese andere Sache wird schließlich eine Funktion aufrufen von Ihnen, um Ihnen das Ergebnis mitzuteilen. Oder? Sie müssen also irgendwie den Namen dieser Funktion angeben (die Rückruffunktion). Die "Schnittstelle!" gibt nur den Namen dieser Funktion an. Das ist alles, mehr gibt es nicht.
2 Stimmen
Der Klassiker
List lst = new ArrayList();
bedeutet nur, dass Sie einschränken, welche Funktionen des erstellten Objekts Ihnen zur Verfügung stehen, was völlig dumm ist. Dieses seltsame Konstrukt wird von Java-Lehrern und -Büchern ohne ersichtlichen Grund immer wieder propagiert.0 Stimmen
@Damien, Sie sollten diese Frage nicht mit weiteren Fragen verwechseln. SO ist eine Seite mit 1 Frage pro Thema. Es ist besser, separate Fragen zu stellen und auf diese Frage zu verweisen, wenn sie relevant ist.
2 Stimmen
@Nyerguds Heiliger Bimbam, ganz und gar nicht! Ein Stück Code sollte den engstmöglichen Typ verwenden, da es sich um selbstdokumentierenden Code handelt. Durch diese Einschränkung des Typs weiß ein Programmierer automatisch mehr darüber, wie er verwendet werden könnte. Nehmen wir einen Code, der Folgendes verwendet
ArrayList
. Es könnte tatsächlich etwas Spezielles für diese Implementierung in der Verwendung von ihr erfordern. Dann denken Sie daran, dass SieIterable
- Sie wissen jetzt zu 100 %, dass der Code nur in einer for each-Schleife verwendet wird. Auf diese Weise wird viel mehr Information in einem verständlichen Code vermittelt.0 Stimmen
@user904963 Das bedeutet auch, dass Ihre Funktion eingeschränkt nur für eine Schleife zu verwenden. Das könnte Ihnen bei späteren Aktualisierungen in den Hintern beißen, wenn Sie drei Funktionen tiefer in das Projekt einsteigen.
1 Stimmen
@Nyerguds Ein ähnliches Problem kann auftreten, wenn Sie einen unnötig spezifischen Typ anfordern. Sie können die Implementierung niemals durch einen verwandten Typ ersetzen, der anders implementiert ist. Es ist ein unzulässiger Kurzschluss in der Logik, Allgemeinheit in einem Code als "völlig dumm" zu bezeichnen. Jede Art von Allgemeinheit/Spezifität hat ihren Zweck, aber im Allgemeinen bietet Ihnen die Verwendung des am wenigsten spezifischen Typs die meisten Möglichkeiten, den Code zu ändern. Fragen Sie nach einer
ArrayList
ist beispielsweise nur dann sinnvoll, wenn ein Teil Ihrer API eine Geschwindigkeitsgarantie ist, die auf zusammenhängenden Speicher angewiesen ist. Der meiste Code wird nur eineList
.0 Stimmen
@user904963 Ist nicht ArrayList buchstäblich die einzige Implementierung von List auf Java sowieso?
1 Stimmen
@Nyerguds Nur für die Standardimplementierungen, die in Java eingebaut sind, schauen Sie sich hier "implementiert von" an: docs.oracle.com/javase/8/docs/api/java/util/List.html . Es gibt
AbstractList
,AbstractSequentialList
,ArrayList
,AttributeList
,CopyOnWriteArrayList
,LinkedList
,RoleList
,RoleUnresolvedList
,Stack
etVector
. Sie können auch benutzerdefinierte Klassen erstellen, die dieList
Schnittstelle oder verwenden Sie den Code anderer Personen, die sie implementieren.