927 Stimmen

Was bedeutet es, "auf eine Schnittstelle zu programmieren"?

Ich habe das schon ein paar Mal gehört und weiß nicht, was es bedeutet. Wann und warum sollten Sie dies tun?

Ich weiß, was Schnittstellen bewirken, aber die Tatsache, dass ich mir darüber nicht im Klaren bin, lässt mich glauben, dass ich sie nicht richtig nutze.

Ist es einfach so, wenn Sie das tun würden:

IInterface classRef = new ObjectWhatever()

Sie können jede Klasse verwenden, die IInterface ? Wann sollten Sie das tun? Das Einzige, was mir einfällt, ist, wenn Sie eine Methode haben und sich nicht sicher sind, welches Objekt außer der Implementierung der Methode übergeben werden soll. IInterface . Ich kann mir nicht vorstellen, wie oft Sie das tun müssen.

Und wie kann man eine Methode schreiben, die ein Objekt aufnimmt, das eine Schnittstelle implementiert? Ist das möglich?

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.

5voto

Shaun Luttin Punkte 119521

Es kann von Vorteil sein, an Schnittstellen zu programmieren, auch wenn wir nicht von Abstraktionen abhängig sind.

Programmierung an Schnittstellen zwingt uns dazu, eine kontextabhängige Teilmenge eines Objekts zu verwenden . Das hilft, weil es:

  1. verhindert, dass wir kontextuell unangemessene Dinge tun, und
  2. können wir die Implementierung in der Zukunft sicher ändern.

Nehmen wir zum Beispiel eine Person Klasse, die die Friend und die Employee Schnittstelle.

class Person implements AbstractEmployee, AbstractFriend {
}

Im Zusammenhang mit dem Geburtstag der Person programmieren wir zum Friend Schnittstelle, um zu verhindern, dass die Person wie ein Employee .

function party() {
    const friend: Friend = new Person("Kathryn");
    friend.HaveFun();
}

Im Zusammenhang mit der Arbeit der Person, programmieren wir auf die Employee Schnittstelle, um zu verhindern, dass die Grenzen am Arbeitsplatz verschwimmen.

function workplace() {
    const employee: Employee = new Person("Kathryn");
    employee.DoWork();
}

Großartig. Wir haben uns in verschiedenen Kontexten angemessen verhalten, und unsere Software funktioniert gut.

In ferner Zukunft, wenn sich unser Geschäft auf die Arbeit mit Hunden umstellt, können wir die Software relativ einfach ändern. Zunächst erstellen wir eine Dog Klasse, die beides implementiert Friend y Employee . Dann ändern wir sicher new Person() à new Dog() . Selbst wenn beide Funktionen Tausende von Codezeilen haben, wird diese einfache Bearbeitung funktionieren, weil wir wissen, dass die folgenden Punkte zutreffen:

  1. Funktion party verwendet nur die Friend Teilmenge von Person .
  2. Funktion workplace verwendet nur die Employee Teilmenge von Person .
  3. Klasse Dog implementiert sowohl die Friend y Employee Schnittstellen.

Andererseits, wenn entweder party ou workplace programmiert haben sollten gegen Person würde das Risiko bestehen, dass beide Person -spezifischen Code. Der Wechsel von Person à Dog müssten wir den Code durchkämmen, um alle Person -spezifischer Code, der Dog nicht unterstützt.

Die Moral Programmierung für Schnittstellen: Die Programmierung für Schnittstellen hilft unserem Code, sich angemessen zu verhalten und auf Veränderungen vorbereitet zu sein. Außerdem bereitet es unseren Code auf die Abhängigkeit von Abstraktionen vor, was noch mehr Vorteile bringt.

1 Stimmen

Vorausgesetzt, Sie haben keine übermäßig breiten Schnittstellen, das heißt.

5voto

Wenn ich eine neue Klasse schreibe Swimmer um die Funktionalität hinzuzufügen swim() und müssen ein Objekt der Klasse Dog und diese Dog Klasse implementiert Schnittstelle Animal die besagt, dass swim() .

An der Spitze der Hierarchie ( Animal ), ist es sehr abstrakt, während es unten ( Dog ) ist es sehr konkret. Die Art und Weise, wie ich über "Programmierung auf Schnittstellen" denke, ist, dass ich schreibe Swimmer Klasse, möchte ich meinen Code gegen die Schnittstelle schreiben, die in dieser Hierarchie am weitesten oben steht, was in diesem Fall eine Animal Objekt. Eine Schnittstelle ist frei von Implementierungsdetails und macht Ihren Code somit lose gekoppelt.

Die Implementierungsdetails können im Laufe der Zeit geändert werden, was sich jedoch nicht auf den übrigen Code auswirkt, da Sie nur mit der Schnittstelle und nicht mit der Implementierung interagieren. Es ist Ihnen egal, wie die Implementierung aussieht... Sie wissen nur, dass es eine Klasse geben wird, die die Schnittstelle implementieren wird.

4voto

Sanjay Rabari Punkte 2045

Kurze Geschichte: Ein Briefträger wird gebeten, nach Hause zu gehen und die darin enthaltenen Briefe (Briefe, Dokumente, Schecks, Geschenkkarten, Bewerbungen, Liebesbrief) mit der darauf geschriebenen Adresse zuzustellen.

Angenommen, es gibt keine Deckung und der Briefträger wird gebeten, von Haus zu Haus zu gehen und alle Sachen in Empfang zu nehmen und an andere Leute zu liefern, dann kann der Briefträger verwirrt werden.

Es ist also besser, ihn mit einer Hülle zu umhüllen (in unserer Geschichte ist es die Schnittstelle), dann wird er seine Arbeit gut machen.

Die Aufgabe des Postboten besteht nun darin, nur die Umschläge entgegenzunehmen und zuzustellen (er würde sich nicht darum kümmern, was sich im Umschlag befindet).

Erstellen Sie einen Typ von interface nicht den tatsächlichen Typ, sondern die Implementierung mit dem tatsächlichen Typ.

Eine Schnittstelle zu erstellen bedeutet, dass Ihre Komponenten Leicht in den Rest des Codes zu integrieren

Ich gebe Ihnen ein Beispiel.

haben Sie die AirPlane-Schnittstelle wie unten dargestellt.

interface Airplane{
    parkPlane();
    servicePlane();
}

Angenommen, Sie haben in Ihrer Controller-Klasse von Planes Methoden wie

parkPlane(Airplane plane)

und

servicePlane(Airplane plane)

in Ihrem Programm implementiert. Es wird nicht UNTERBRECHUNG Ihren Code. Ich meine, er muss sich nicht ändern, solange er Argumente als AirPlane .

Denn es wird jedes Flugzeug trotz des aktuellen Typs akzeptiert, flyer , highflyr , fighter など。

Auch in einer Sammlung:

List<Airplane> plane; // Wird alle Ihre Flugzeuge nehmen.

Das folgende Beispiel soll Ihnen das Verständnis erleichtern.


Sie haben ein Kampfflugzeug, das es einsetzt, also

public class Fighter implements Airplane {

    public void  parkPlane(){
        // Specific implementations for fighter plane to park
    }
    public void  servicePlane(){
        // Specific implementatoins for fighter plane to service.
    }
}

Das Gleiche gilt für HighFlyer und andere Klassen:

public class HighFlyer implements Airplane {

    public void  parkPlane(){
        // Specific implementations for HighFlyer plane to park
    }

    public void  servicePlane(){
        // specific implementatoins for HighFlyer plane to service.
    }
}

Denken Sie nun Ihre Controller-Klassen mit AirPlane mehrere Male,

Angenommen, Ihre Controller-Klasse ist ControlPlane wie unten,

public Class ControlPlane{ 
 AirPlane plane;
 // so much method with AirPlane reference are used here...
}

Hier kommt Magie ins Spiel, denn Sie können Ihr neues AirPlane Instanzen des Typs so viele Sie wollen und Sie ändern nicht den Code von ControlPlane Klasse.

Sie können eine Instanz hinzufügen...

JumboJetPlane // implementing AirPlane interface.
AirBus        // implementing AirPlane interface.

Sie können auch Instanzen von zuvor erstellten Typen entfernen.

4voto

Richard Punkte 963

Sie eignet sich auch gut für Unit-Tests, da Sie Ihre eigenen Klassen (die die Anforderungen der Schnittstelle erfüllen) in eine Klasse injizieren können, die von ihr abhängt

3voto

Trae Barlow Punkte 31

C++ Erklärung.

Stellen Sie sich eine Schnittstelle als die öffentlichen Methoden Ihrer Klasse vor.

Sie könnten dann eine Vorlage erstellen, die von diesen öffentlichen Methoden "abhängig" ist, um ihre eigene Funktion auszuführen (sie führt Funktionsaufrufe aus, die in der öffentlichen Schnittstelle der Klasse definiert sind). Nehmen wir an, diese Vorlage ist ein Container, wie eine Vektorklasse, und die Schnittstelle, von der sie abhängt, ist ein Suchalgorithmus.

Jede Algorithmusklasse, die die Funktionen/Schnittstelle definiert, die Vector aufruft, erfüllt den "Vertrag" (wie jemand in der ursprünglichen Antwort erklärte). Die Algorithmen müssen nicht einmal derselben Basisklasse angehören; die einzige Voraussetzung ist, dass die Funktionen/Methoden, von denen der Vector abhängt (Schnittstelle), in Ihrem Algorithmus definiert sind.

Der Sinn des Ganzen ist, dass Sie jeden beliebigen Suchalgorithmus/jede beliebige Suchklasse anbieten können, solange er/sie die Schnittstelle bietet, von der Vector abhängt (Blasensuche, sequentielle Suche, Schnellsuche).

Sie könnten auch andere Container (Listen, Warteschlangen) entwerfen, die denselben Suchalgorithmus wie Vector nutzen, indem sie die Schnittstelle/Vertrag erfüllen, von der Ihr Suchalgorithmus abhängt.

Dies spart Zeit (OOP-Grundsatz "Wiederverwendung von Code"), da Sie einen Algorithmus nur einmal schreiben müssen und nicht immer wieder für jedes neue Objekt, das Sie erstellen, ohne die Sache durch einen ausufernden Vererbungsbaum zu verkomplizieren.

Was das "Verpassen" der Funktionsweise angeht, so ist das (zumindest in C++) von entscheidender Bedeutung, da der größte Teil des Frameworks der Standard TEMPLATE Library auf diese Weise funktioniert.

Natürlich ändert sich bei der Verwendung von Vererbung und abstrakten Klassen die Methodik der Programmierung für eine Schnittstelle, aber das Prinzip ist das gleiche: Ihre öffentlichen Funktionen/Methoden sind die Schnittstelle Ihrer Klasse.

Dies ist ein großes Thema und eines der Grundprinzipien von Design Patterns.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X