“Programm zu einer Schnittstelle”. Was heißt das?

Mögliche Duplikate:
Was bedeutet es, “auf eine Schnittstelle zu programmieren”?

Ich stoße immer wieder auf diesen Begriff:

Programm zu einer Schnittstelle.

Was genau bedeutet es? Ein realistisches Design-Szenario würde sehr geschätzt werden.

Solutions Collecting From Web of "“Programm zu einer Schnittstelle”. Was heißt das?"

Um es einfach auszudrücken, anstatt deine classn so zu schreiben, wie es heißt

Ich bin auf diese spezielle class angewiesen, um meine Arbeit zu machen

du schreibst es so, wie es heißt

Ich bin auf jede class angewiesen, die das Zeug macht , um meine Arbeit zu machen.

Das erste Beispiel stellt eine class dar, die von einer konkreten Implementierung abhängt, um ihre Arbeit zu erledigen. Inhärent ist das nicht sehr flexibel.

Das zweite Beispiel stellt eine class dar, die in eine Schnittstelle geschrieben wurde . Es ist egal, welches konkrete Objekt du benutzt, es kümmert nur, dass es bestimmtes Verhalten implementiert. Dies macht die class viel flexibler, da sie mit einer beliebigen Anzahl von konkreten Implementierungen ausgestattet werden kann, um ihre Arbeit zu erledigen.

Als Beispiel muss eine bestimmte class eine Protokollierung durchführen. Wenn Sie die class so schreiben, dass sie von einem TextFileLogger abhängt, wird die class für immer gezwungen, ihre Protokolldatensätze in eine Textdatei zu schreiben. Wenn Sie das Verhalten der Protokollierung ändern möchten, müssen Sie die class selbst ändern. Die class ist eng mit ihrem Logger gekoppelt.

Wenn Sie jedoch schreiben, dass die class von einer ILogger-Schnittstelle abhängt, und dann die class mit einem TextFileLogger ausstatten, haben Sie dasselbe erreicht, aber mit dem zusätzlichen Vorteil, viel flexibler zu sein. Sie können jede andere Art von ILogger nach Belieben bereitstellen, ohne die class selbst zu ändern. Die class und ihr Logger sind jetzt lose gekoppelt, und Ihre class ist viel flexibler.

Eine Schnittstelle ist eine Sammlung von verwandten Methoden, die nur die Signaturen dieser Methoden enthält – nicht die eigentliche Implementierung.
Wenn eine class eine Schnittstelle implementiert ( class Car implements IDrivable ), muss sie Code für alle in der Schnittstelle definierten Signaturen bereitstellen.

Grundbeispiel:
Sie müssen classn Auto und Fahrrad. Beide implementieren die Schnittstelle IDrivable:

 interface IDrivable { void accelerate(); void brake(); } 

 class Car implements IDrivable { void accelerate() { System.out.println("Vroom"); } void brake() { System.out.println("Queeeeek");} } 

 class Bike implements IDrivable { void accelerate() { System.out.println("Rattle, Rattle, ..."); } void brake() { System.out.println("..."); } } 

Nehmen wir an, Sie haben eine Sammlung von Objekten, die alle “befahrbar” sind (ihre classn implementieren alle IDrivable):

 List vehicleList = new ArrayList(); list.add(new Car()); list.add(new Car()); list.add(new Bike()); list.add(new Car()); list.add(new Bike()); list.add(new Bike()); 

Wenn Sie nun diese Auflistung durchlaufen möchten, können Sie sich darauf verlassen, dass jedes Objekt in dieser Sammlung die Methode accelerate() implementiert:

 for(IDrivable vehicle: vehicleList) { vehicle.accelerate(); //this could be a bike or a car, or anything that implements IDrivable } 

Wenn Sie diese Schnittstellenmethode aufrufen, programmieren Sie nicht für eine Implementierung, sondern für eine Schnittstelle – ein Vertrag, der sicherstellt, dass das Aufrufziel eine bestimmte functionalität implementiert.
Das gleiche Verhalten könnte unter Verwendung der inheritance erreicht werden, aber das Ableiten von einer gemeinsamen Basisklasse führt zu einer engen Kopplung, die unter Verwendung von Schnittstellen vermieden werden kann.

Polymorphismus hängt von der Programmierung an einer Schnittstelle ab, nicht von einer Implementierung.

Es gibt zwei Vorteile, Objekte nur in Bezug auf die von abstrakten classn definierte Schnittstelle zu manipulieren:

  1. Die Clients sind sich der spezifischen Objekttypen, die sie verwenden, nicht bewusst, solange sich die Objekte an der Schnittstelle halten, die die Clients erwarten.
  2. Clients sind sich der classn, die diese Objekte implementieren, nicht bewusst. Clients kennen nur die abstrakten classn, die die Schnittstelle definieren.

Dies reduziert die Implementierungsabhängigkeiten zwischen Subsystemen so stark, dass es zu diesem Prinzip der Programmierung einer Schnittstelle führt.

Weitere Informationen zu diesem Entwurf finden Sie im Factory Method-Muster .

Quelle: ” Design Patterns: Elemente wiederverwendbarer objektorientierter Software ” von GOF

Siehe auch: Fabrikmuster. Wann werden die Fabrikmethoden verwendet?

Beispiele aus der realen Welt sind reichlich vorhanden. Einer von ihnen:

Für JDBC verwenden Sie die Schnittstelle java.sql.Connection . Jeder JDBC-Treiber stellt jedoch eine eigene Implementierung von Connection bereit. Sie müssen nichts über die jeweilige Implementierung wissen, da sie der Connection Schnittstelle entspricht.

Eine andere stammt aus dem Java-Collections-Framework. Es gibt eine java.util.Collection Schnittstelle, die size definiert, Methoden add und remove (neben vielen anderen). So können Sie alle Arten von Sammlungen austauschbar verwenden . Nehmen wir an, Sie haben Folgendes:

 public float calculateCoefficient(Collection collection) { return collection.size() * something / somethingElse; } 

Und zwei andere Methoden, die diesen aufrufen. Eine der anderen Methoden verwendet eine LinkedList da sie für ihre Zwecke effizienter ist und die andere ein TreeSet .

Da sowohl LinkedList als auch TreeSet die Collection Schnittstelle implementieren, können Sie nur eine Methode zur Koeffizientenberechnung verwenden. Keine Notwendigkeit, Ihren Code zu duplizieren.

Und hier kommt das “Programm zu einer Schnittstelle” – es ist dir egal, wie genau die size() -Methode implementiert ist, du weißt, dass es die Größe der Sammlung zurückgeben soll – dh du hast auf die Collection Oberfläche programmiert, statt auf LinkedList und TreeSet .

Aber mein Rat ist, eine Lektüre zu finden – vielleicht ein Buch (“Thinking in Java” zum Beispiel) – wo das Konzept im Detail erklärt wird.

Jedes Objekt hat eine exponierte Schnittstelle. Eine Sammlung hat Add , Remove , At , usw. Ein Socket kann Send , Receive , Close und so weiter haben.

Jedes Objekt, auf das Sie tatsächlich zugreifen können, hat eine konkrete Implementierung dieser Schnittstellen.

Beide Dinge sind offensichtlich, aber was ist weniger offensichtlich …

Ihr Code sollte sich nicht auf die Implementierungsdetails eines Objekts verlassen, sondern nur auf die veröffentlichte Schnittstelle.

Wenn Sie es zu einem Extrem führen, würden Sie nur gegen Collection und so weiter kodieren (anstatt ArrayList ). Praktisch, stellen Sie sicher, dass Sie etwas konzeptionell identisch eintauschen können, ohne Ihren Code zu brechen.

Um das Collection Beispiel herauszufiltern: Sie haben eine Sammlung von etwas, Sie verwenden eigentlich ArrayList warum nicht . Sie sollten sicherstellen, dass der Code nicht bricht, wenn Sie beispielsweise LinkedList in Zukunft verwenden.

Es bedeutet im Grunde, dass der einzige Teil der Bibliothek, auf den Sie sich verlassen sollten, seine API (Anwendungsprogrammierschnittstelle) ist und dass Sie Ihre Anwendung nicht auf der konkreten Implementierung der Bibliothek basieren sollten.

z.B. Angenommen, Sie haben eine Bibliothek, die Ihnen einen stack . Die class gibt Ihnen ein paar Methoden. Sagen wir push , pop , isempty und top . Sie sollten Ihre Anwendung nur auf diesen basieren schreiben. Eine Möglichkeit, dies zu verletzen, wäre, nach innen zu schauen und herauszufinden, dass der Stack mit einem Array von einer Art implementiert wurde. Wenn Sie von einem leeren Stack abspringen, erhalten Sie eine Art Index-Ausnahme und fangen diese dann ein sich auf die isempty Methode verlassen, die die class bereitstellt. Der erstgenannte Ansatz würde fehlschlagen, wenn der Bibliotheksanbieter von der Verwendung eines Arrays zu einer Art Liste überging, während die letztere immer noch funktionierte, vorausgesetzt, der Provider behielt seine API immer noch in Betrieb.

“Programmieren auf eine Schnittstelle” passiert, wenn Sie Bibliotheken verwenden, anderen Code, auf den Sie in Ihrem eigenen Code angewiesen sind. Dann stellt die Art und Weise, wie sich der andere Code für Sie darstellt, die Methodennamen, ihre Parameter, Rückgabewerte usw. die Schnittstelle dar , auf die Sie programmieren müssen. Es geht also darum, wie Sie Code von Drittanbietern verwenden.

Es bedeutet auch, dass Sie sich nicht um die Interna des Codes kümmern müssen, auf den Sie angewiesen sind, solange das Interface gleich bleibt, Ihr Code sicher ist (naja, mehr oder weniger …)

Technisch gibt es feinere Details, wie zum Beispiel Sprachkonzepte, die in Java “Interfaces” genannt werden.

Wenn Sie mehr erfahren möchten, können Sie sich fragen, was “Implementierung einer Schnittstelle” bedeutet …

Ich denke, das ist eines von Erich Gammas Mantras. Ich kann das erste Mal nicht finden, dass er es beschrieben hat (vor dem GOF-Buch), aber Sie können es in einem Interview unter http://www.artima.com/lejava/articles/designprinciples.html sehen