wake-up-neo.com

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

Ich habe dies einige Male erwähnt und ich bin mir nicht klar, was es bedeutet. Wann und warum würdest du das tun? 

Ich weiß, was Schnittstellen tun, aber die Tatsache, dass ich nicht klar bin, lässt mich vermuten, dass ich sie nicht richtig nutze. 

Ist es nur so, wenn Sie tun würden:

IInterface classRef = new ObjectWhatever()

Sie können eine beliebige Klasse verwenden, die IInterface implementiert. Wann müsstest du das tun? Das einzige, woran ich denken kann, ist, wenn Sie eine Methode haben und nicht sicher sind, welches Objekt übergeben wird, außer dass es IInterface implementiert. Ich kann mir nicht vorstellen, wie oft Sie das tun müssten. 

Wie könnten Sie auch eine Methode schreiben, die ein Objekt aufnimmt, das eine Schnittstelle implementiert? Ist das möglich?

746
Damien

Es gibt hier einige wunderbare Antworten auf diese Fragen, die alle möglichen Details zu Schnittstellen und lose Kopplung von Code, Umkehrung der Kontrolle und so weiter enthalten. Es gibt einige recht aufregende Diskussionen, daher möchte ich die Gelegenheit nutzen, die Dinge ein wenig aufzuschlüsseln, um zu verstehen, warum eine Schnittstelle nützlich ist.

Als ich anfing, Schnittstellen kennenzulernen, war auch ich verwirrt über ihre Relevanz. Ich habe nicht verstanden, warum du sie brauchst. Wenn wir eine Sprache wie Java oder C # verwenden, haben wir bereits Vererbung und ich habe Schnittstellen als schwächere Form der Vererbung angesehen und gedacht: "Warum stören?" In gewissem Sinne hatte ich recht, man kann sich Schnittstellen als eine Art schwache Vererbung vorstellen, aber darüber hinaus verstand ich sie schließlich als Sprachkonstrukt, indem ich sie als Mittel zur Klassifizierung gemeinsamer Merkmale oder Verhaltensweisen betrachtete, die von ihnen gezeigt wurden möglicherweise viele nicht zusammenhängende Objektklassen.

Zum Beispiel - Sie haben ein SIM-Spiel und die folgenden Klassen:

class HouseFly inherits Insect {
    void FlyAroundYourHead(){}
    void LandOnThings(){}
}

class Telemarketer inherits Person {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}
}

Offensichtlich haben diese beiden Objekte in Bezug auf die direkte Vererbung nichts gemeinsam. Aber man könnte sagen, beide sind nervig. 

Nehmen wir an, unser Spiel muss eine Art zufälliges Ding haben, das den Spieler beim Abendessen ärgert. Dies kann eine HouseFly oder eine Telemarketer oder beide sein - aber wie lassen sich beide Funktionen mit einer einzigen Funktion ausführen? Und wie bittet man die verschiedenen Objekttypen, auf dieselbe Weise "ihr nerviges Ding zu machen"?

Der Schlüssel zum Erkennen ist, dass sowohl eine Telemarketer als auch eine HouseFly ein gemeinsames, lose interpretiertes Verhalten gemeinsam haben, auch wenn sie sich bei der Modellierung nicht unterscheiden. Lassen Sie uns also eine Schnittstelle erstellen, die beide implementieren können:

interface IPest {
    void BeAnnoying();
}

class HouseFly inherits Insect implements IPest {
    void FlyAroundYourHead(){}
    void LandOnThings(){}

    void BeAnnoying() {
        FlyAroundYourHead();
        LandOnThings();
    }
}

class Telemarketer inherits Person implements IPest {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}

    void BeAnnoying() {
        CallDuringDinner();
        ContinueTalkingWhenYouSayNo();
    }
}

Wir haben jetzt zwei Klassen, die jeweils auf ihre Weise nervig sein können. Und sie müssen nicht von derselben Basisklasse abgeleitet sein und gemeinsame inhärente Merkmale aufweisen - sie müssen lediglich den Vertrag von IPest erfüllen - dieser Vertrag ist einfach. Sie müssen nur BeAnnoying. In dieser Hinsicht können wir Folgendes modellieren:

class DiningRoom {

    DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

    void ServeDinner() {
        when diningPeople are eating,

        foreach pest in pests
        pest.BeAnnoying();
    }
}

Hier haben wir einen Speisesaal, der eine Reihe von Gästen und eine Reihe von Schädlingen akzeptiert - beachten Sie die Verwendung der Schnittstelle. Dies bedeutet, dass in unserer kleinen Welt ein Mitglied des pests-Arrays tatsächlich ein Telemarketer-Objekt oder ein HouseFly-Objekt sein kann.

Die ServeDinner-Methode wird aufgerufen, wenn das Abendessen serviert wird und unsere Leute im Speisesaal essen sollen. In unserem kleinen Spiel machen unsere Schädlinge ihre Arbeit - jeder Schädling wird aufgefordert, über die IPest-Schnittstelle zu ärgern. Auf diese Weise können wir leicht Telemarketers und HouseFlys auf jede eigene Weise ärgern - wir kümmern uns nur darum, dass wir etwas in dem DiningRoom-Objekt haben, das eine Plage ist, uns egal, was es ist und was sie können habe nichts mit anderen gemeinsam. 

Dieses sehr erfundene Pseudocodebeispiel (das sich viel länger als erwartet in die Länge zog) soll lediglich veranschaulichen, was für ein Licht letztendlich das Licht für mich in Bezug auf die Verwendung einer Schnittstelle auslöste. Ich entschuldige mich im Voraus für die Dummheit des Beispiels, hoffe jedoch, dass es zu Ihrem Verständnis beiträgt. Um sicher zu sein, die anderen geposteten Antworten, die Sie hier erhalten haben, decken die Bandbreite der heutigen Verwendung von Schnittstellen in Entwurfsmustern und Entwicklungsmethoden ab. 

1486
Peter Meyer

Das spezifische Beispiel, das ich den Schülern gegeben habe, ist, dass sie schreiben sollten

List myList = new ArrayList(); // programming to the List interface

anstatt

ArrayList myList = new ArrayList(); // this is bad

Diese sehen in einem kurzen Programm genau gleich aus, aber wenn Sie myList 100 Mal in Ihrem Programm verwenden, können Sie einen Unterschied feststellen. Die erste Deklaration stellt sicher, dass Sie nur Methoden für myList aufrufen, die von der List-Schnittstelle definiert werden (also keine ArrayList-spezifischen Methoden). Wenn Sie das Interface auf diese Weise programmiert haben, können Sie später entscheiden, ob Sie es wirklich brauchen

List myList = new TreeList();

und Sie müssen Ihren Code nur an dieser einen Stelle ändern. Sie wissen bereits, dass der Rest Ihres Codes nichts tut, was durch die Änderung der Implementierung beschädigt wird, weil Sie auf die Schnittstelle programmiert haben.

Die Vorteile sind noch deutlicher (denke ich), wenn Sie über Methodenparameter und Rückgabewerte sprechen. Nehmen Sie dies zum Beispiel:

public ArrayList doSomething(HashMap map);

Diese Methodendeklaration bindet Sie an zwei konkrete Implementierungen (ArrayList und HashMap). Sobald diese Methode aus einem anderen Code aufgerufen wird, müssen Sie bei Änderungen an diesen Typen wahrscheinlich auch den aufrufenden Code ändern. Es ist besser, die Schnittstellen zu programmieren.

public List doSomething(Map map);

Nun ist es egal, welche Art von List Sie zurückgeben oder welche Art von Map als Parameter übergeben wird. Änderungen, die Sie in der doSomething-Methode vornehmen, zwingen Sie nicht, den aufrufenden Code zu ändern.

249
Bill the Lizard

Bei der Programmierung einer Schnittstelle heißt es: "Ich brauche diese Funktionalität und es ist mir egal, woher sie kommt."

Betrachten Sie (in Java) die List-Schnittstelle gegenüber den konkreten ArrayList- und LinkedList-Klassen. Wenn es mir nur darum geht, dass ich eine Datenstruktur habe, die mehrere Datenelemente enthält, auf die ich per Iteration zugreifen sollte, würde ich eine List auswählen (und das ist zu 99% die Zeit). Wenn ich weiß, dass ich konstantes Einfügen/Löschen an einem Ende der Liste benötige, wähle ich möglicherweise die konkrete Implementierung der Variablen LinkedList (oder verwenden Sie eher die Queue - Schnittstelle). Wenn ich weiß, dass ich per Index einen Direktzugriff benötige, würde ich die konkrete Klasse ArrayList auswählen.

66
kdgregory

Die Verwendung von Schnittstellen ist ein Schlüsselfaktor dafür, dass Ihr Code leicht testbar ist und nicht nur unnötige Kopplungen zwischen Ihren Klassen entfernt werden müssen. Durch das Erstellen einer Schnittstelle, die die Vorgänge in Ihrer Klasse definiert, gestatten Sie Klassen, die diese Funktionalität verwenden möchten, die Möglichkeit, sie zu verwenden, ohne von der implementierenden Klasse direkt abhängig zu sein. Wenn Sie sich später entscheiden, eine andere Implementierung zu ändern und zu verwenden, müssen Sie nur den Teil des Codes ändern, in dem die Implementierung instanziiert wird. Der Rest des Codes muss nicht geändert werden, da er von der Schnittstelle und nicht von der implementierenden Klasse abhängt.

Dies ist sehr hilfreich beim Erstellen von Komponententests. In der getesteten Klasse müssen Sie es von der Schnittstelle abhängig machen und eine Instanz der Schnittstelle über den Konstruktor oder einen Eigenschaftsausgleich in die Klasse (oder eine Factory, die es erlaubt, Instanzen der Schnittstelle nach Bedarf zu erstellen) einfügen. Die Klasse verwendet die bereitgestellte (oder erstellte) Schnittstelle in ihren Methoden. Wenn Sie Ihre Tests schreiben, können Sie die Schnittstelle simulieren oder fälschen und eine Schnittstelle bereitstellen, die mit den in Ihrem Gerätetest konfigurierten Daten reagiert. Sie können dies tun, da sich Ihre getestete Klasse nur mit der Schnittstelle befasst, nicht mit Ihrer konkreten Implementierung. Jede Klasse, die die Schnittstelle implementiert, einschließlich Ihrer Mock- oder Fake-Klasse, kann dies tun.

EDIT: Nachfolgend finden Sie einen Link zu einem Artikel, in dem Erich Gamma sein Zitat bespricht: "Programm für eine Schnittstelle, keine Implementierung".

http://www.artima.com/lejava/articles/designprinciples.html

35
tvanfosson

Sie sollten sich Inversion of Control ansehen:

In einem solchen Szenario würden Sie das nicht schreiben:

IInterface classRef = new ObjectWhatever();

Sie würden so etwas schreiben:

IInterface classRef = container.Resolve<IInterface>();

Dies würde in ein regelbasiertes Setup im container-Objekt eingehen und das eigentliche Objekt für Sie erstellen, 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 funktioniert weiterhin.

Wenn IoC nicht in der Tabelle vorhanden ist, können Sie Code schreiben, der weiß, dass er mit einem Objekt sprechen kann, das etwas bestimmtes ausführt, aber nicht welcher Objekttyp oder wie er ausgeführt wird.

Dies wäre praktisch, wenn Sie Parameter übergeben.

Zu Ihrer Frage in Klammern "Wie können Sie auch eine Methode schreiben, die ein Objekt einfügt, das eine Schnittstelle implementiert? Ist das möglich?", Würden Sie in C # einfach den Schnittstellentyp für den Parametertyp verwenden:

public void DoSomethingToAnObject(IInterface whatever) { ... }

Dies wird direkt in das "Sprechen mit einem Objekt, das etwas bestimmtes tut" eingesteckt. Die oben definierte Methode weiß, was von dem Objekt zu erwarten ist, dass es alles in IInterface implementiert, es ist jedoch egal, um welche Art von Objekt es sich handelt, nur dass es sich an den Vertrag hält, was eine Schnittstelle ist.

Zum Beispiel kennen Sie sich wahrscheinlich mit Taschenrechnern aus und haben in Ihrer Zeit wahrscheinlich einige verwendet, aber meistens sind sie alle verschieden. Sie wissen andererseits, wie ein Standard-Taschenrechner funktionieren sollte. Sie können also alle verwenden, auch wenn Sie nicht die spezifischen Funktionen eines jeden Rechners verwenden können, die keiner der anderen besitzt.

Das ist die Schönheit der Schnittstellen. Sie können einen Code schreiben, der weiß, dass ihm Objekte übergeben werden, von denen er ein bestimmtes Verhalten erwarten kann. Es ist egal, was für ein Objekt es ist, nur dass es das erforderliche Verhalten unterstützt.

Lassen Sie mich ein konkretes Beispiel geben.

Wir haben ein maßgeschneidertes Übersetzungssystem für Windows-Formulare. Dieses System durchläuft Steuerelemente in einem Formular und übersetzt jeweils Text. Das System weiß, wie grundlegende Steuerelemente wie die Steuerelementtypen-Eigenschaft, die über eine Text-Eigenschaft verfügt, und ähnliche grundlegende Elemente behandelt werden müssen. Für grundlegende Elemente ist dies jedoch unzureichend.

Da Steuerelemente von vordefinierten Klassen erben, auf die wir keinen Einfluss haben, können wir eine der drei folgenden Aktionen ausführen:

  1. Bauen Sie Unterstützung für unser Übersetzungssystem auf, um genau festzustellen, mit welcher Art von Steuerung es arbeitet, und übersetzen Sie die richtigen Bits (Wartungs-Albtraum).
  2. Unterstützung in Basisklassen einbauen (unmöglich, da alle Steuerelemente von verschiedenen vordefinierten Klassen erben)
  3. Schnittstellenunterstützung hinzufügen

Also haben wir nr. 3. Alle unsere Steuerelemente implementieren ILocalizable, eine Schnittstelle, die uns eine Methode gibt, nämlich die Möglichkeit, "sich selbst" in einen Container mit Übersetzungstext/Regeln zu übersetzen. Daher muss das Formular nicht wissen, welche Art von Steuerelement es gefunden hat, sondern nur, dass es die spezifische Schnittstelle implementiert, und weiß, dass es eine Methode gibt, mit der es aufgerufen werden kann, um das Steuerelement zu lokalisieren.

Die Programmierung einer Schnittstelle hat absolut nichts mit abstrakten Schnittstellen zu tun, wie wir sie in Java oder .NET sehen. Es ist nicht einmal ein OOP Konzept.

Was es wirklich bedeutet, ist, dass Sie nicht mit den Internen eines Objekts oder einer Datenstruktur herumspielen. Verwenden Sie die abstrakte Programmoberfläche oder API, um mit Ihren Daten zu interagieren. In Java oder C # bedeutet dies die Verwendung öffentlicher Eigenschaften und Methoden anstelle des Rohfeldzugriffs. Für C bedeutet das, Funktionen anstelle von Rohzeigern zu verwenden.

BEARBEITEN: Bei Datenbanken bedeutet das, Ansichten und gespeicherte Prozeduren anstelle des direkten Tabellenzugriffs zu verwenden.

29
Jonathan Allen

Code für die Schnittstelle Weder die Implementierung noch das Interface-Konstrukt haben etwas mit Java zu tun.

Dieses Konzept wurde in den Patterns/Gang of Four-Büchern in den Vordergrund gerückt, war aber höchstwahrscheinlich schon lange vorher bekannt. Das Konzept existierte zweifellos schon lange bevor Java überhaupt existierte.

Das Interface-Konstrukt Java) wurde erstellt, um diese Idee zu unterstützen (unter anderem), und die Leute haben sich zu sehr auf das Konstrukt als das Zentrum der Bedeutung und nicht auf die ursprüngliche Absicht konzentriert ist der Grund, warum wir öffentliche und private Methoden und Attribute in Java, C++, C # usw. haben.

Es bedeutet, nur mit einem Objekt oder der öffentlichen Schnittstelle eines Systems zu interagieren. Machen Sie sich keine Sorgen und nehmen Sie nicht einmal vorweg, wie es intern funktioniert. Mach dir keine Sorgen darüber, wie es implementiert wird. Im objektorientierten Code gibt es deshalb öffentliche und private Methoden/Attribute. Wir beabsichtigen, die öffentlichen Methoden zu verwenden, da die privaten Methoden nur für die interne Verwendung innerhalb der Klasse vorgesehen sind. Sie bilden die Implementierung der Klasse und können nach Bedarf geändert werden, ohne die öffentliche Schnittstelle zu ändern. Nehmen Sie an, dass eine Methode für eine Klasse in Bezug auf die Funktionalität bei jedem Aufruf mit denselben Parametern dieselbe Operation mit denselben erwarteten Ergebnissen ausführt. Sie ermöglicht dem Autor, die Funktionsweise und Implementierung der Klasse zu ändern, ohne die Interaktion der Benutzer zu beeinträchtigen.

Und Sie können auf die Schnittstelle programmieren, nicht auf die Implementierung, ohne jemals ein Interface-Konstrukt zu verwenden. Sie können auf die Schnittstelle programmieren, nicht auf die Implementierung in C++ habe kein Interface-Konstrukt. Sie können zwei massive Unternehmenssysteme viel robuster integrieren, solange sie über öffentliche Schnittstellen (Verträge) interagieren, anstatt Methoden für systeminterne Objekte aufzurufen. Es wird erwartet, dass die Schnittstellen bei gleichen Eingabeparametern immer auf die gleiche erwartete Weise reagieren. wenn implementiert auf die Schnittstelle und nicht die Implementierung. Das Konzept funktioniert an vielen Orten.

Schütteln Sie den Gedanken ab, dass Java Interfaces irgendetwas mit dem Konzept von 'Programm an die Schnittstelle, nicht die Implementierung' zu tun haben. Sie können helfen, das Konzept anzuwenden, aber sie sind - nicht das Konzept.

25
Bill Rosmus

Es klingt, als würden Sie verstehen, wie Schnittstellen funktionieren, sind sich jedoch nicht sicher, wann sie verwendet werden sollen und welche Vorteile sie bieten. Hier einige Beispiele, wann eine Schnittstelle sinnvoll wäre:

// if I want to add search capabilities to my application and support multiple search
// engines such as google, yahoo, live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

dann könnte ich GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider usw. erstellen.

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

erstellen Sie dann JpegImageLoader, GifImageLoader, PngImageLoader usw.

Die meisten Add-Ins und Pluginsysteme arbeiten mit Schnittstellen.

Eine weitere beliebte Anwendung ist das Repository-Muster. Angenommen, ich möchte eine Liste von Postleitzahlen aus verschiedenen Quellen laden

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

dann könnte ich ein XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository usw. erstellen. Für meine Webanwendungen erstelle ich häufig XML-Repositorys, damit ich etwas einrichten kann, bevor die SQL-Datenbank bereit ist. Sobald die Datenbank fertig ist, schreibe ich ein SQLRepository, um die XML-Version zu ersetzen. Der Rest meines Codes bleibt unverändert, da er nur von Schnittstellen abläuft.

Methoden können Schnittstellen akzeptieren wie:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}
12
Todd Smith

Es macht Ihren Code viel erweiterbarer und einfacher zu verwalten, wenn Sie ähnliche Klassen haben. Ich bin ein Junior-Programmierer, also kein Experte, aber ich habe gerade ein Projekt abgeschlossen, das etwas Ähnliches erforderte.

Ich arbeite an clientseitiger Software, die mit einem Server kommuniziert, auf dem ein medizinisches Gerät ausgeführt wird. Wir entwickeln eine neue Version dieses Geräts, die einige neue Komponenten enthält, die der Kunde zuweilen konfigurieren muss. Es gibt zwei Arten von neuen Komponenten, die sich unterscheiden, aber sie sind sich auch sehr ähnlich. Grundsätzlich musste ich zwei Konfigurationsformulare erstellen, zwei Klassen und zwei Klassen. 

Ich entschied, dass es am besten ist, eine abstrakte Basisklasse für jeden Steuerelementtyp zu erstellen, die fast die gesamte Logik enthält, und dann abgeleitete Typen, um die Unterschiede zwischen den beiden Komponenten zu berücksichtigen. Die Basisklassen wären jedoch nicht in der Lage, Vorgänge an diesen Komponenten auszuführen, wenn ich mich ständig um Typen kümmern müsste. .

Ich habe eine einfache Schnittstelle für diese Komponenten definiert, und alle Basisklassen sprechen mit dieser Schnittstelle. Wenn ich jetzt etwas ändere, funktioniert es praktisch überall und ich habe keine Code-Vervielfältigung.

10
Ed S.

Wenn Sie in Java programmieren, ist JDBC ein gutes Beispiel. JDBC definiert eine Reihe von Schnittstellen, sagt jedoch nichts zur Implementierung aus. Ihre Anwendungen können gegen diesen Satz von Schnittstellen geschrieben werden. Theoretisch wählen Sie einen JDBC-Treiber aus und Ihre Anwendung würde funktionieren. Wenn Sie feststellen, dass es einen schnelleren oder "besseren" oder günstigeren JDBC-Treiber gibt oder aus welchem ​​Grund auch immer, können Sie Ihre Eigenschaftendatei theoretisch erneut konfigurieren. Ohne Ihre Anwendung ändern zu müssen, funktioniert Ihre Anwendung trotzdem.

8

Das Programmieren von Schnittstellen ist großartig, es fördert lose Kopplung. Wie von @lassevk erwähnt, ist Inversion of Control eine großartige Verwendung davon.

Schauen Sie sich außerdem die SOLID -Prinzipale an. hier ist eine Videoserie

Es durchläuft ein hartcodiertes (stark gekoppeltes Beispiel), betrachtet dann Schnittstellen und geht schließlich zu einem IoC/DI-Tool (NInject) über.

8
dbones

Ich bin ein Spätwanderer dieser Frage, aber ich möchte hier erwähnen, dass die Zeile "Programm zu einer Schnittstelle, nicht zu einer Implementierung" eine gute Diskussion im GoF (Gang of Four) Design Patterns-Buch hatte.

Es stellte fest, auf p. 18

Programm auf eine Schnittstelle, keine Implementierung

Deklarieren Sie Variablen nicht als Instanzen bestimmter konkreter Klassen. Festschreiben Sie stattdessen nur an eine Schnittstelle, die von einer abstrakten Klasse definiert wird. Sie werden feststellen, dass dies ein gemeinsames Thema der Designmuster in diesem Buch ist.

und darüber begann es mit:

Es gibt zwei Vorteile, Objekte nur im Hinblick auf die durch abstrakte Klassen definierte Schnittstelle zu bearbeiten:

  1. Clients wissen nicht, welche speziellen Objekttypen sie verwenden, solange die Objekte der von den Clients erwarteten Schnittstelle entsprechen.
  2. Die Clients wissen nicht, welche Klassen diese Objekte implementieren. Kunden wissen nur über die abstrakten Klassen, die die Schnittstelle definieren.

Mit anderen Worten, schreiben Sie Ihre Klassen nicht so, dass sie eine quack()-Methode für Enten und dann eine bark()-Methode für Hunde haben, da sie zu spezifisch für eine bestimmte Implementierung einer Klasse (oder Unterklasse) sind. Schreiben Sie die Methode stattdessen mit Namen, die allgemein genug sind, um in der Basisklasse verwendet zu werden, z. B. giveSound() oder move(), so dass sie für Enten, Hunde oder sogar Autos verwendet werden können .giveSound(), anstatt darüber nachzudenken, ob quack() oder bark() verwendet werden soll oder sogar den Typ zu bestimmen, bevor die richtige Nachricht ausgegeben wird, die an das Objekt gesendet werden soll.

Es gibt eine Menge Erklärungen da draußen, aber um es noch einfacher zu machen ... __ Nehmen Sie zum Beispiel ein List Man kann eine Liste implementieren mit: 

  1. ein internes Array
  2. Eine verknüpfte Liste
  3. andere Implementierung

Sagen Sie List, indem Sie eine Schnittstelle erstellen. Sie schreiben nur die Definition von List oder was List in Wirklichkeit bedeutet.

Sie könnten jede Art von Implementierung intern verwenden, beispielsweise eine array-Implementierung. Angenommen, Sie möchten die Implementierung aus irgendeinem Grund ändern, beispielsweise einen Fehler oder eine Leistung. Dann müssen Sie nur noch die Deklaration List<String> ls = new ArrayList<String>() in List<String> ls = new LinkedList<String>() ändern.

An keiner anderen Stelle im Code müssen Sie etwas anderes ändern. Weil alles andere auf der Definition von List basiert. 

6
Jatin

Zusätzlich zu der bereits ausgewählten Antwort (und den verschiedenen informativen Beiträgen hier) würde ich dringend empfehlen, sich eine Kopie von Head First Design Patterns zu schnappen. Es ist sehr einfach zu lesen und wird Ihre Frage direkt beantworten, erklären, warum es wichtig ist, und Ihnen viele Programmiermuster zeigen, die Sie verwenden können, um dieses Prinzip (und andere) anzuwenden.

6
whaley

Um bestehende Posts hinzuzufügen, hilft das Codieren von Schnittstellen manchmal bei großen Projekten, wenn Entwickler gleichzeitig an separaten Komponenten arbeiten. Sie müssen lediglich Schnittstellen definieren und ihnen Code schreiben, während andere Entwickler Code an die Schnittstelle schreiben, die Sie implementieren.

4
edgi

Es eignet sich auch für Unit Testing. Sie können Ihre eigenen Klassen (die die Anforderungen der Schnittstelle erfüllen) in eine davon abhängige Klasse einfügen

4
Richard

Um dies richtig zu machen, besteht der Vorteil einer Schnittstelle darin, dass ich den Aufruf einer Methode von einer bestimmten Klasse trennen kann. Stattdessen wird eine Instanz der Schnittstelle erstellt, bei der die Implementierung von der Klasse erfolgt, die ich auswähle, um diese Schnittstelle zu implementieren. Dies erlaubt mir, viele Klassen zu haben, die eine ähnliche, aber leicht abweichende Funktionalität haben, und in einigen Fällen (in den Fällen, die mit der Intention der Schnittstelle zusammenhängen), es egal ist, um welches Objekt es sich handelt.

Zum Beispiel könnte ich eine Bewegungsschnittstelle haben. Eine Methode, die etwas „bewegt“ und jedes Objekt (Person, Auto, Katze), das die Bewegungsschnittstelle implementiert, kann übergeben werden und kann sich bewegen. Ohne die Methode weiß jeder, welche Art von Klasse es ist. 

3
Damien

C++ - Erklärung.

Stellen Sie sich eine Schnittstelle als öffentliche Methoden Ihrer Klassen vor.

Sie könnten dann eine Vorlage erstellen, die von diesen öffentlichen Methoden 'abhängt', 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 wie eine Vector-Klasse ein Container und die Schnittstelle, von der sie abhängt, ist ein Suchalgorithmus.

Jede Algorithmusklasse, die die Funktionen/Schnittstellen definiert, an die Vector Aufrufe vornimmt, erfüllt den 'Vertrag' (wie in der ursprünglichen Antwort erläutert). Die Algorithmen müssen nicht einmal von derselben Basisklasse sein; Die einzige Voraussetzung ist, dass die Funktionen/Methoden, von denen der Vector abhängig ist (Schnittstelle), in Ihrem Algorithmus definiert sind.

Der Sinn von all dem ist, dass Sie einen anderen Suchalgorithmus/eine andere Klasse angeben können, solange er die Schnittstelle bereitstellt, von der Vector abhängig ist (Blasensuche, sequenzielle Suche, Schnellsuche).

Möglicherweise möchten Sie auch andere Container (Listen, Warteschlangen) entwerfen, die den gleichen Suchalgorithmus wie Vector nutzen, indem Sie die Schnittstelle/den Vertrag erfüllen, von der Ihre Suchalgorithmen abhängen.

Dies spart Zeit (OOP-Prinzip 'Wiederverwendung von Code'), da Sie in der Lage sind, einen Algorithmus einmal und nicht immer wieder spezifisch für jedes neue Objekt zu erstellen, das Sie erstellen, ohne das Problem durch einen zu großen Vererbungsbaum zu komplizieren.

Wie "verpasst es", wie Dinge funktionieren; (zumindest in C++), da dies in der Regel der Rahmen der Standard TEMPLATE Library ist.

Bei der Verwendung von Vererbungs- und abstrakten Klassen ändert sich natürlich die Methodik der Programmierung einer Schnittstelle. Das Prinzip ist jedoch dasselbe, Ihre öffentlichen Funktionen/Methoden sind Ihre Klassenschnittstelle.

Dies ist ein riesiges Thema und eines der Grundprinzipien von Design Patterns.

3
Trae Barlow

Stellen Sie sich vor, Sie haben ein Produkt namens "Zebra", das durch Plugins erweitert werden kann. Es findet die Plugins durch Suchen nach DLLs in einem Verzeichnis. Es lädt alle diese DLLs und verwendet Reflektion, um Klassen zu finden, die IZebraPlugin implementieren, und ruft dann die Methoden dieser Schnittstelle auf, um mit den Plugins zu kommunizieren. 

Dies macht es völlig unabhängig von einer bestimmten Plugin-Klasse - es ist ihnen egal, was die Klassen sind. Es ist nur wichtig, dass sie die Schnittstellenspezifikation erfüllen. 

Schnittstellen sind eine Möglichkeit, Erweiterungspunkte wie diese zu definieren. Code, der mit einer Schnittstelle kommuniziert, ist locker gekoppelt - er ist überhaupt nicht an einen anderen spezifischen Code gekoppelt. Es kann mit Plugins zusammenarbeiten, die Jahre später von Personen geschrieben wurden, die den ursprünglichen Entwickler noch nie kennengelernt haben.

Sie können stattdessen eine Basisklasse mit virtuellen Funktionen verwenden - alle Plugins würden von der Basisklasse abgeleitet. Dies ist jedoch viel einschränkender, da eine Klasse nur eine Basisklasse haben kann, während sie eine beliebige Anzahl von Schnittstellen implementieren kann.

3

In Java implementieren diese konkreten Klassen alle die CharSequence-Schnittstelle:

CharBuffer, String, StringBuffer, StringBuilder

Diese konkreten Klassen haben keine gemeinsame übergeordnete Klasse außer Object, daher gibt es nichts, was sie miteinander in Verbindung bringt, außer dass sie jeweils etwas mit Arrays von Zeichen zu tun haben, solche repräsentieren oder solche manipulieren. Zum Beispiel können die Zeichen von String nicht geändert werden, sobald ein String-Objekt instanziiert wird, während die Zeichen von StringBuffer oder StringBuilder bearbeitet werden können.

Jede dieser Klassen kann jedoch die CharSequence-Schnittstellenmethoden geeignet implementieren:

char charAt(int index)
int length()
CharSequence subSequence(int start, int end)
String toString()

In einigen Fällen wurden Java-Klassenbibliotheksklassen, die zuvor String akzeptiert haben, überarbeitet und akzeptieren nun die CharSequence-Schnittstelle. Wenn Sie also über eine Instanz von StringBuilder verfügen, anstatt ein String-Objekt zu extrahieren (dh eine neue Objektinstanz zu instantiieren), können Sie stattdessen einfach den StringBuilder selbst übergeben, während er die CharSequence-Schnittstelle implementiert.

Die Appendable-Schnittstelle, die von einigen Klassen implementiert wird, hat in jeder Situation, in der Zeichen an eine Instanz der zugrunde liegenden konkreten Klassenobjektinstanz angehängt werden können, den gleichen Vorteil. Alle diese konkreten Klassen implementieren die Appendable-Schnittstelle:

BufferedWriter, CharArrayWriter, CharBuffer, FileWriter, FilterWriter, LogStream, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, StringBuffer, StringBuilder, StringWriter, Writer

2
RogerV

Es kann vorteilhaft sein, Schnittstellen zu programmieren, auch wenn wir nicht auf Abstraktionen angewiesen sind.

Programmierung von Interfaces zwingt uns, eine kontextuell passende Teilmenge eines Objekts zu verwenden. Das hilft, weil es: 

  1. hindert uns daran, kontextuell unangemessene Dinge zu tun, und 
  2. lässt uns die Implementierung in Zukunft sicher ändern.

Stellen Sie sich beispielsweise eine Person-Klasse vor, die die Friend- und die Employee-Schnittstelle implementiert.

class Person implements AbstractEmployee, AbstractFriend {

}

Im Zusammenhang mit dem Geburtstag der Person programmieren wir die Friend-Schnittstelle, um zu verhindern, dass die Person wie eine Employee behandelt wird.

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

Im Rahmen der Arbeit der Person programmieren wir die Employee-Schnittstelle, um ein Verschwimmen der Arbeitsplatzgrenzen zu vermeiden.

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

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

Wenn sich unser Geschäft für die Arbeit mit Hunden ändert, können wir die Software ziemlich leicht ändern. Zuerst erstellen wir eine Dog-Klasse, die sowohl Friend als auch Employee implementiert. Dann ändern wir sicher new Person() in new Dog(). Selbst wenn beide Funktionen Tausende von Codezeilen haben, funktioniert diese einfache Bearbeitung, da wir wissen, dass die folgenden Bedingungen zutreffen:

  1. Die Funktion party verwendet nur die Friend-Teilmenge von Person
  2. Die Funktion workplace verwendet nur die Employee-Teilmenge von Person
  3. Die Klasse Dog implementiert die Schnittstellen Friend und Employee

Wenn dagegen entweder party oder workplace gegen Person programmiert werden sollte, besteht das Risiko, dass beide Person-spezifischen Code haben. Wenn Sie von Person zu Dog wechseln, müssen Sie den Code durchkämmen, um Person-spezifischen Code zu löschen, den Dog nicht unterstützt.

Die Moral : Programmierung von Interfaces hilft unserem Code, sich angemessen zu verhalten und bereit für Veränderungen zu sein. Es bereitet auch unseren Code darauf vor, sich auf Abstraktionen zu verlassen, was noch mehr Vorteile bringt. 

2
Shaun Luttin

In einfachen Worten ... Wenn ich eine neue Klasse Swimmer schreibe, um die Funktionalität swim () hinzuzufügen und ein Objekt der Klasse verwenden zu müssen, sagen Sie Dog, und diese Dog-Klasse implementiert die Schnittstelle Animal, die das Schwimmen erklärt () [Um besser zu verstehen ... können Sie ein Diagramm zeichnen, worüber ich spreche]. Am oberen Ende der Hierarchie (Tier) ist es sehr abstrakt, während es am unteren Ende (Hund) sehr konkret ist. Was ich über "Programmierung für Schnittstellen" denke, ist, dass ich beim Schreiben der Swimmer-Klasse meinen Code gegen die Schnittstelle schreiben möchte, die so weit oben in der Hierarchie liegt, in diesem Fall Animal-Objekt. Eine Schnittstelle ist frei von Implementierungsdetails und macht Ihren Code somit locker gekoppelt. Die Implementierungsdetails können mit der Zeit geändert werden. Der verbleibende Code wird jedoch nicht beeinflusst, da Sie nur mit der Schnittstelle und nicht mit der Implementierung interagieren. Es ist Ihnen egal, wie die Implementierung ist ... Sie wissen nur, dass es eine Klasse gibt, die die Schnittstelle implementiert.

kurzgeschichte: Postbote wird gebeten, von zu Hause nach Hause zu gehen und die Briefe zu erhalten (Briefe, Dokumente, Schecks, Geschenkkarte, Antrag, Liebesbrief) mit der darauf geschriebenen Adresse.

Nehmen Sie an, es gibt keine Deckung und bitten Sie den Postboten, von zu Hause nach Hause zu gehen und alle Dinge zu empfangen und an andere Personen zu liefern, die der Postbote verwirren kann.

also besser wickle es mit einem Cover ein (in unserer Geschichte ist es Interface), dann wird er seine Arbeit gut machen.

Jetzt ist der Postbote-Job nur für den Erhalt und die Zustellung der Briefe zuständig. (Er kümmert sich nicht darum, was sich in der Brieftasche befindet).

Erstellen Sie den Typ interface, nicht den tatsächlichen Typ, sondern implementieren Sie ihn mit dem tatsächlichen Typ.

Create to interface bedeutet, dass Ihre Komponenten passt sich leicht in den restlichen Code ein

Ich gebe dir ein Beispiel.

sie haben die AirPlane-Schnittstelle wie folgt.

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

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

parkPlane(Airplane plane)

und

servicePlane(Airplane plane)

in Ihrem Programm implementiert. Es wird nicht BREAK Ihr Code .. _. Ich meine, es muss nicht geändert werden, solange es Argumente als AirPlane akzeptiert.

Da es jedes Flugzeug trotz des tatsächlichen Typs akzeptieren kann, flyer, highflyr, fighter usw.

Auch in einer Sammlung:

List<Airplane> plane; // Nimm all deine Flugzeuge mit.

Das folgende Beispiel verdeutlicht Ihr Verständnis.


Sie haben ein Kampfflugzeug, das es implementiert, 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.
    }
}

Dasselbe 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 jetzt daran, dass Ihre Controller-Klassen mehrmals AirPlane verwenden,

Angenommen, Ihre Controller-Klasse ist ControlPlane (siehe unten).

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

hier kommt Magie als 

sie können Ihre neuen AirPlane-Instanzen beliebig viele machen und Sie ändern sich nicht 

code der ControlPlane-Klasse.

sie können Instanz hinzufügen ..

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

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

2
Sanjay Rabari

Eine Schnittstelle ist wie ein Vertrag, bei dem Sie möchten, dass Ihre Implementierungsklasse im Vertrag geschriebene Methoden (Schnittstelle) implementiert. Da Java keine Mehrfachvererbung bietet, ist "Programmieren in Schnittstelle" eine gute Möglichkeit, Mehrfachvererbung zu erreichen.

Wenn Sie über eine Klasse A verfügen, die bereits eine andere Klasse B erweitert, aber auch Klasse A bestimmte Richtlinien befolgen oder einen bestimmten Vertrag implementieren möchten, können Sie dies mit der Strategie "Programmieren mit Schnittstelle" tun.

2
Shivam Sugandhi

Programm zu einer Schnittstelle ermöglicht die nahtlose Änderung der Implementierung des durch die Schnittstelle definierten Vertrags. Es ermöglicht eine lose Kopplung zwischen Vertrag und spezifischen Implementierungen.

IInterface classRef = new ObjectWhatever()

Sie könnten jede Klasse verwenden, die IInterface implementiert? Wann müssten Sie das tun?

Schauen Sie sich diese SE-Frage als gutes Beispiel an.

Warum sollte die Schnittstelle für eine Java Klasse bevorzugt werden?

schlägt die Verwendung eines Interfaces die Performance?

wenn ja wie viel?

Ja. In Sekundenbruchteilen entsteht ein geringer Leistungsaufwand. Wenn Ihre Anwendung jedoch eine dynamische Änderung der Schnittstellenimplementierung erfordert, müssen Sie sich keine Gedanken über die Auswirkungen auf die Leistung machen.

wie können Sie dies vermeiden, ohne zwei Codebits verwalten zu müssen?

Versuchen Sie nicht, mehrere Schnittstellenimplementierungen zu vermeiden, wenn Ihre Anwendung diese benötigt. In Ermangelung einer engen Kopplung der Schnittstelle mit einer bestimmten Implementierung müssen Sie möglicherweise den Patch bereitstellen, um eine Implementierung in eine andere zu ändern.

Ein guter Anwendungsfall: Umsetzung des Strategiemusters:

Reales Beispiel des Strategiemusters

1
Ravindra babu

F: - ... "Sie können jede Klasse verwenden, die die Schnittstelle implementiert?"
A: - Ja.

F: -... "Wann müssten Sie das tun?"
A: - Jedes Mal, wenn Sie eine Klasse (n) benötigen, die eine oder mehrere Schnittstellen implementiert.

Hinweis: _ ​​eine Schnittstelle, die nicht von einer Klasse implementiert wurde, konnte nicht instanziiert werden - True. 

  • warum? 
  • weil das Interface nur Methodenprototypen hat, nicht Definitionen (nur Funktionsnamen, nicht ihre Logik) 

AnIntf ​​anInst = new Aclass ();
// wir könnten dies nur tun, wenn Aclass AnIntf ​​implementiert.
// anInst wird eine Aclass-Referenz haben.


Hinweis:
Jetzt könnten wir verstehen, was passiert, wenn Bclass und Cclass den gleichen Dintf implementieren.

Dintf bInst = new Bclass();  
// now we could call all Dintf functions implemented (defined) in Bclass.

Dintf cInst = new Cclass();  
// now we could call all Dintf functions implemented (defined) in Cclass.

Was wir haben:
gleichen Schnittstellenprototypen (Funktionsnamen in der Schnittstelle) und rufen verschiedene Implementierungen auf.

Literaturverzeichnis:
Prototypen - wikipedia

1
user1630938

Ich behalte nicht, dass interfaces das Wichtigste in einer Sprache ist: Es wird häufiger die erbende Klasse verwendet. Aber auf jeden Fall sind sie wichtig!
Zum Beispiel (dies ist Java code, kann aber einfach an C# oder viele andere Sprachen angepasst werden):

interface Convertable<T> {

    T convert();
}

public class NumerableText implements Convertable<Integer> {

    private String text = "";

    public NumerableText() { }

    public NumerableText(String text) {
        this.text = text;
    }

    public String getText() {
        return this.text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Integer convert() {
        return this.text.hashCode();
    }
}

public class NumerableTextArray implements Convertable<Integer> {

    private String[] textArray = "";

    public NumerableTextArray() { }

    public NumerableTextArray(String[] textArray) {
        this.textArray = textArray;
    }

    public String[] getTextArray() {
        return this.textArray;
    }

    public void setTextArray(String[] text) {
        this.textArray = textArray;
    }

    public Integer convert() {
        Integer value = 0;
        for (String text : textArray)
            value += text.hashCode();
        return value;
    }
}

public class Foo {

    public static void main() {
        Convertable<Integer> num1 = new NumerableText("hello");
        Convertable<Integer> num2 = new NumerableTextArray(new String[] { "test n°1", "test n°2" });
        System.out.println(String.valueOf(num1.convert()));
        System.out.println(String.valueOf(num2.convert()));
        //Here are you two numbers generated from two classes of different type, but both with the method convert(), which allows you to get that number.
    }
}
0
Davide Cannizzo

Beginnen wir zunächst mit einigen Definitionen:

Schnittstelle n.Die Menge aller Signaturen, die durch die Operationen eines Objekts definiert werden, wird als Schnittstelle zum Objekt bezeichnet

Typ n.Eine bestimmte Schnittstelle

Ein einfaches Beispiel für eine Schnittstelle , wie oben definiert, wären alle PDO-Objektmethoden wie query(), commit(), close() usw. als Ganzes, nicht separat. Diese Methoden, d. H. Ihre Schnittstelle, definieren den vollständigen Satz von Nachrichten, Anforderungen, die an das Objekt gesendet werden können.

Ein Typ wie oben definiert ist eine bestimmte Schnittstelle. Ich werde die hergestellte Formschnittstelle verwenden, um zu demonstrieren: draw(), getArea(), getPerimeter() etc ..

Wenn ein Objekt vom Typ "Database" ist, meinen wir, dass es Nachrichten/Anforderungen der Datenbankschnittstelle, query(), commit() usw., akzeptiert. Objekte können verschiedene Typen haben. Sie können ein Datenbankobjekt vom Formtyp haben, solange es seine Schnittstelle implementiert. In diesem Fall wäre dies Untertyp .

Viele Objekte können viele verschiedene Schnittstellen/Typen haben und diese Schnittstellen unterschiedlich implementieren. Dies ermöglicht uns, Objekte zu ersetzen und uns entscheiden zu lassen, welches Objekt verwendet werden soll. Auch als Polymorphismus bekannt.

Der Client kennt nur die Schnittstelle und nicht die Implementierung. 

Das Programmieren einer Schnittstelle würde also im Wesentlichen die Erstellung einer Art abstrakter Klasse wie Shape mit nur der angegebenen Schnittstelle umfassen, dh draw(), getCoordinates(), getArea() usw.. Dreieck-Klasse. Also Programm zu einer Schnittstelle keine Implementierung.

0
Robert Rocha

"Program to interface" bedeutet, dass Sie keinen harten Code bereitstellen müssen. Das bedeutet, dass Ihr Code erweitert werden sollte, ohne die vorherige Funktionalität zu beeinträchtigen. Nur Erweiterungen, nicht den vorherigen Code bearbeiten.

0
ndoty

Ich bin der festen Überzeugung, dass schwierige Fragen mit einfachen realen Antworten erklärt werden sollten. Und im Bereich Software-Design ist das sehr wichtig.

Schauen Sie sich eine Tür in Ihrem Haus, Ihrer Schule, Kirche ... ein Gebäude an.

Stellen Sie sich vor, einige Türen haben die Gefahren rechts unten (Sie müssen sich also verneigen, um mit der Tür zu interagieren, die geöffnet oder geschlossen ist),

Oder andere haben gerade in der oben links (also werden einige Zwerge, Menschen mit Behinderungen oder Kevin Hart solche Türen nicht sehr amüsant und brauchbar finden).

Also Design ist das Schlüsselwort, erstellen Sie Programme für andere Menschen können entwickeln/verwenden.

Was Interfaces macht, ist, es anderen Junior-/Senior-Entwicklern in Koloss-Projekten leicht zu machen [1] , damit jeder weiß, was sie mit der geringen Hilfe anderer tun, damit Sie so reibungslos wie möglich arbeiten können (in Theorie).

[1] Wie ?. durch Freilegen der Form von Wert. Sie benötigen also keine Dokumentation, da der Code selbsterklärend ist (Awesome).

Diese Antwort sollte nicht sprachspezifisch sein, sondern konzeptionell (Immerhin Menschen Erstellen von Werkzeugen durch Schreiben von Code).

0
Yoarthur

Ich sehe hier auch viele gute und erklärende Antworten, daher möchte ich hier meinen Standpunkt erläutern und einige zusätzliche Informationen dazu enthalten, was mir bei der Verwendung dieser Methode aufgefallen ist.

Stückprüfung

Ich habe in den letzten zwei Jahren ein Hobbyprojekt geschrieben und keine Komponententests dafür geschrieben. Nachdem ich ungefähr 50.000 Zeilen geschrieben hatte, stellte ich fest, dass es wirklich notwendig war, Komponententests zu schreiben. Ich benutzte keine Schnittstellen (oder sehr sparsam) ... und als ich meinen ersten Komponententest durchführte, stellte ich fest, dass es kompliziert war. Warum?

Weil ich viele Klasseninstanzen erstellen musste, die als Klassenvariablen und/oder Parameter verwendet wurden. Die Tests sehen also eher wie Integrationstests aus (sie müssen ein komplettes "Framework" für Klassen erstellen, da alle miteinander verbunden sind).

Angst vor Schnittstellen .__ Also entschied ich mich für Schnittstellen. Meine Befürchtung war, dass ich alle Funktionen (in allen verwendeten Klassen) mehrmals implementieren musste. In gewisser Weise trifft dies zu, jedoch kann durch die Verwendung von Vererbung eine erhebliche Verringerung erzielt werden.

Kombination von Schnittstellen und Vererbung Ich fand heraus, dass die Kombination sehr gut ist. Ich gebe ein sehr einfaches Beispiel.

public interface IPricable
{
    int Price { get; }
}

public interface ICar : IPricable

public abstract class Article
{
    public int Price { get { return ... } }
}

public class Car : Article, ICar
{
    // Price does not need to be defined here
}

Auf diese Weise ist das Kopieren von Code nicht erforderlich, während gleichzeitig der Vorteil besteht, dass ein Auto als Schnittstelle (ICar) verwendet wird.

0
Michel Keijzers