Sie sollten sich mit der Umkehrung der Kontrolle befassen:
In einem solchen Szenario würden Sie dies nicht schreiben:
IInterface classRef = new ObjectWhatever();
Sie würden etwa so schreiben:
IInterface classRef = container.Resolve<IInterface>();
Dies würde in eine regelbasierte Einrichtung in der container
Objekt und konstruieren das eigentliche Objekt für Sie, das ObjectWhatever sein könnte. Das Wichtigste ist, dass Sie diese Regel durch etwas ersetzen könnten, das einen anderen Objekttyp verwendet, und Ihr Code würde trotzdem funktionieren.
Wenn wir IoC vom Tisch lassen, können Sie Code schreiben, der weiß, dass er mit einem Objekt sprechen kann die etwas Bestimmtes tut aber nicht, welche Art von Objekt oder wie es dies tut.
Dies wäre bei der Übergabe von Parametern nützlich.
Was Ihre Frage in Klammern angeht: "Wie kann man eine Methode schreiben, die ein Objekt aufnimmt, das eine Schnittstelle implementiert? Ist das möglich?", würden Sie in C# einfach den Schnittstellentyp für den Parametertyp verwenden, etwa so:
public void DoSomethingToAnObject(IInterface whatever) { ... }
Dies fügt sich nahtlos in die "Rede mit einem Objekt, das etwas Bestimmtes tut" ein. Die oben definierte Methode weiß, was sie von dem Objekt zu erwarten hat, nämlich dass es alles in IInterface implementiert, aber es ist ihr egal, um welche Art von Objekt es sich handelt, sie will nur, dass es sich an den Vertrag hält, was eine Schnittstelle ist.
Zum Beispiel sind Sie wahrscheinlich mit Taschenrechnern vertraut und haben in Ihrem Leben schon einige benutzt, aber meistens sind sie alle unterschiedlich. Sie hingegen wissen, wie ein Standardtaschenrechner funktionieren sollte. Sie können sie also alle benutzen, auch wenn Sie die spezifischen Funktionen, die jeder Taschenrechner hat und die keiner der anderen hat, nicht nutzen können.
Das ist das Schöne an Schnittstellen. Man kann ein Stück Code schreiben, das weiß, dass es Objekte übergeben bekommt, von denen es ein bestimmtes Verhalten erwarten kann. Dabei ist es völlig egal, um welche Art von Objekt es sich handelt, Hauptsache, es unterstützt das gewünschte Verhalten.
Ich möchte Ihnen ein konkretes Beispiel nennen.
Wir haben ein maßgeschneidertes Übersetzungssystem für Windows-Formulare entwickelt. Dieses System durchläuft die Steuerelemente eines Formulars und übersetzt den Text in jedem einzelnen. Das System weiß, wie man mit grundlegenden Steuerelementen umgeht, wie z. B. dem Typ des Steuerelements, das eine Texteigenschaft hat, und ähnlichen grundlegenden Dingen, aber für alles, was grundlegend ist, reicht es nicht aus.
Da Steuerelemente von vordefinierten Klassen erben, über die wir keine Kontrolle haben, gibt es drei Möglichkeiten, wie wir vorgehen können:
- Unterstützung für unser Übersetzungssystem, um zu erkennen, mit welcher Art von Steuerung es arbeitet, und die richtigen Bits zu übersetzen (Wartungsalptraum)
- Unterstützung in Basisklassen einbauen (unmöglich, da alle Steuerelemente von verschiedenen vordefinierten Klassen erben)
- Schnittstellenunterstützung hinzufügen
Alle unsere Steuerelemente implementieren ILocalizable, eine Schnittstelle, die uns eine Methode zur Verfügung stellt, nämlich die Möglichkeit, "sich selbst" in einen Container mit Übersetzungstext/Regeln zu übersetzen. Das Formular muss also nicht wissen, welche Art von Steuerelement es gefunden hat, es muss nur wissen, dass es die spezifische Schnittstelle implementiert und dass es eine Methode gibt, die es aufrufen kann, um das Steuerelement zu lokalisieren.
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?!?
82 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.
1 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.
0 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?
0 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.