Warum sind Schnittstellen nützlich?


158

Ich lerne und programmiere seit einiger Zeit in C #. Trotzdem kann ich die Nützlichkeit von Schnittstellen nicht beurteilen. Sie bringen zu wenig auf den Tisch. Abgesehen von der Bereitstellung der Funktionssignaturen tun sie nichts. Wenn ich mich an die Namen und Unterschriften der Funktionen erinnern kann, die implementiert werden müssen, sind sie nicht erforderlich. Sie sind nur dazu da, um sicherzustellen, dass die genannten Funktionen (in der Schnittstelle) in der übernehmenden Klasse implementiert sind.

C # ist eine großartige Sprache, aber manchmal hat man das Gefühl, dass Microsoft das Problem zuerst erstellt (keine Mehrfachvererbung zulässt) und dann die Lösung bereitstellt, die ziemlich langwierig ist.

Das ist mein Verständnis, das auf begrenzten Codierungserfahrungen basiert. Was halten Sie von Schnittstellen? Wie oft benutzt du sie und wie oft machst du das?


55
"Wenn ich mir die Namen und Unterschriften der Funktionen merken kann, die implementiert werden müssen, sind sie nicht erforderlich." Diese Aussage lässt mich vermuten, dass Sie die Vorteile statisch typisierter Sprachen etwas genauer untersuchen sollten .
Steven Jeuris

37
Vergiss C #, vergiss Java, vergiss die Sprache. Es ist einfach in OO zu denken. Ich möchte Sie ermutigen, sich Lesematerial von Leuten wie Robert C. Martin, Martin Fowler, Michael Feathers, der Viererbande usw. zu besorgen, um Ihr Denken zu erweitern.
Anthony Pegram

27
Ich habe mehr als zwei Jahre gebraucht, um wirklich zu verstehen, wozu Schnittstellen gut sind. Mein Vorschlag: Design Patterns studieren. Da die meisten von ihnen auf Schnittstellen angewiesen sind, werden Sie schnell verstehen, warum sie so nützlich sind.
Oliver Weiler

37
Du musst viel lernen, Freund.
ChaosPandion

60
@ChaosPandion wir haben alle eine Menge zu lernen
Kenwarner

Antworten:


151

Sie sind nur dazu da, um sicherzustellen, dass die genannten Funktionen (in der Schnittstelle) in der übernehmenden Klasse implementiert sind.

Richtig. Das ist ein großartiger Vorteil, der die Funktion rechtfertigt. Wie bereits erwähnt, ist eine Schnittstelle eine vertragliche Verpflichtung zur Implementierung bestimmter Methoden, Eigenschaften und Ereignisse. Der überzeugende Vorteil einer statisch typisierten Sprache besteht darin, dass der Compiler überprüfen kann, ob ein Vertrag, auf den sich Ihr Code stützt, tatsächlich erfüllt ist.

Trotzdem sind Schnittstellen eine ziemlich schwache Möglichkeit, vertragliche Verpflichtungen darzustellen. Wenn Sie eine stärkere und flexiblere Möglichkeit zur Darstellung vertraglicher Verpflichtungen wünschen, schauen Sie sich die Codevertragsfunktion an, die mit der letzten Version von Visual Studio ausgeliefert wurde.

C # ist eine großartige Sprache, aber manchmal hat man das Gefühl, dass Microsoft zuerst das Problem erstellt (keine Mehrfachvererbung zulässt) und dann die Lösung bereitstellt, die ziemlich langwierig ist.

Nun, ich bin froh, dass es dir gefällt.

Alle komplexen Softwaredesigns sind das Ergebnis der Abwägung widersprüchlicher Funktionen und des Versuchs, den "Sweet Spot" zu finden, der große Vorteile bei geringen Kosten bietet. Wir haben durch schmerzhafte Erfahrungen gelernt, dass Sprachen, die eine Mehrfachvererbung zum Zwecke der gemeinsamen Nutzung von Implementierungen ermöglichen, relativ geringe Vorteile und relativ hohe Kosten haben. Das Zulassen der Mehrfachvererbung nur für Schnittstellen, die keine Implementierungsdetails gemeinsam nutzen, bietet viele Vorteile der Mehrfachvererbung, ohne die meisten Kosten zu verursachen.


Ich habe gerade gelesen, "Microsoft schafft das Problem, indem es keine Mehrfachvererbung zulässt", und ich dachte, Eric Lippert hätte etwas dazu zu sagen.
Konfigurator

Noch relevanter für diese Antwort: Eric, Sie verweisen den Fragesteller auf Code Contracts, aber diese sind absolut unvollständig. alles andere als die grundlegendsten Verträge ist vom statischen Prüfer nicht durchsetzbar. Ich habe versucht, Code Contract für ein kleines Projekt zu verwenden. Ich habe Hunderte von Zeilen für jede Methode hinzugefügt, in denen alles angegeben ist, was ich über Ein- und Ausgabe konnte, und dennoch musste ich Assumefür Fälle wie Array- oder Aufzählungsmitglieder so viele Aufrufe hinzufügen . Nachdem ich alles hinzugefügt und das statisch verifizierte Durcheinander gesehen hatte, kehrte ich in die Quellcodeverwaltung zurück, da dies die Qualität meines Projekts beeinträchtigte.
Konfigurator

17
@configurator: Sie sind unvollständig, weil sie nicht vollständig sein können. Eine statische Programmüberprüfung mit beliebigen Verträgen ist gleichbedeutend mit der Lösung des Halteproblems. (Sie könnten beispielsweise einen Codevertrag schreiben, der besagt, dass die Argumente für eine Methode ein Gegenbeispiel zu Fermats letztem Satz sein müssen. Der statische Prüfer kann jedoch nicht überprüfen, ob solche Argumente vorhanden sind.) Ich muss es mit Bedacht anwenden, wenn Sie erwarten, dass der statische Prüfer seine Arbeit vor dem Tod des Universums beendet. (Wenn Ihre Beschwerde lautet, dass die BCL nicht ausreichend kommentiert ist: Ich stimme zu.)
Eric Lippert

2
Ich gehe davon aus, dass wenn eine Methode verspricht, dass das Ergebnisarray oder die Aufzählung keine Null enthält, die using-Methode die Werte an Stellen verwenden kann, die keine Nullen zulassen. Das war das Einzige, was ich erwartet hatte, und es war zu wichtig, um ohne es verwendet werden zu können. alles andere ist nur ein Bonus. Ich weiß jedoch, dass die statische Überprüfung nicht vollständig sein kann, weshalb ich der Meinung bin, dass dies keine gute Alternative ist, um Verträge abzuschließen.
Konfigurator

9
+1 für "Ich bin froh, dass es dir gefällt." Und all die anderen Sachen auch.
Robert S.

235

Bildbeschreibung hier eingeben

In diesem Beispiel weiß der PowerSocket also nichts anderes über die anderen Objekte. Die Objekte hängen alle von der Stromversorgung durch den PowerSocket ab, sodass sie IPowerPlug implementieren und sich damit verbinden können.

Schnittstellen sind nützlich, da sie Verträge bereitstellen, mit denen Objekte zusammenarbeiten können, ohne dass sie etwas anderes voneinander wissen müssen.


4
Das untere linke Objekt sieht nicht so aus, als würde es IPowerPlug implementieren =)
Steven Striga

100
Verdammt, aber wir müssen ein Adaptermuster verwenden, um den IPowerPlug in verschiedenen Ländern zu verwenden!
Steven Jeuris

Jerry-Rigging eines Geräts zur Umgehung der Schnittstelle ist nicht sicher (aber einige Leute führen die Leistung immer noch häufig als ungetestete Entschuldigung an) und kann wahrscheinlich zu Bränden führen.
YoungJohn

4
Diese Antwort ist einfach unglaublich ...
Mario Garcia

Nur auf diese Antwort hinzuweisen, sagt in diesem Beispiel noch nicht aus, warum die Verwendung einer Schnittstelle der Vererbung vorzuziehen ist. Jemand, der noch nicht mit Schnittstellen vertraut ist, fragt sich möglicherweise, warum sie nicht alle von z. B. MainsPoweredDevice erben, das die gesamte Plug-Funktionalität bietet, wobei der Socket alles akzeptiert, was von MainsPoweredDevice abgeleitet ist.
ingredient_15939

145

Abgesehen von der Bereitstellung der Funktionssignaturen tun sie nichts. Wenn ich mir die Namen und Unterschriften der Funktionen merken kann, die implementiert werden müssen, sind sie nicht erforderlich

Die Schnittstelle soll Ihnen nicht dabei helfen, sich an die zu implementierende Methode zu erinnern, sondern dient dazu , einen Vertrag zu definieren . In foreach P.Brian.Mackey-Beispiel (was sich als falsch herausstellt , aber uns egal ist) definiert IEnumerable einen Vertrag zwischen foreach und einer beliebigen zählbaren Sache. Es heißt: "Wer auch immer Sie sind, solange Sie sich an den Vertrag halten (IEnumerable implementieren), ich verspreche Ihnen, ich werde über alle Ihre Elemente iterieren". Und das ist großartig (für eine nicht dynamische Sprache).

Dank der Schnittstellen können Sie eine sehr geringe Kopplung zwischen zwei Klassen erreichen.



Ich mag es nicht, den Begriff "Duck Typing" zu verwenden, weil er für verschiedene Menschen unterschiedliche Bedeutungen hat. Wir verwenden die Mustererkennung für die "foreach" -Schleife, da IEnumerable <T> bei der Entwicklung nicht verfügbar war. Wir verwenden die Mustererkennung für LINQ, weil das C # -Typsystem zu schwach ist, um das von uns benötigte "Monadenmuster" zu erfassen. Sie brauchen so etwas wie das Haskell-Typ-System.
Eric Lippert

@Eric: Hat "Pattern Matching" nicht das gleiche Problem? Wenn ich es höre, denke ich F # / Scala / Haskell. Aber ich denke, es ist eine umfassendere Idee als das Tippen von Enten.
Daniel

@ Daniel: Ja, ich nehme an, es tut. Es ist sechs von einem und einem halben Dutzend der anderen, denke ich!
Eric Lippert

36

Schnittstellen sind der beste Weg, um gut entkoppelte Konstrukte zu erhalten.

Beim Schreiben von Tests werden Sie feststellen, dass konkrete Klassen in Ihrer Testumgebung nicht funktionieren.

Beispiel: Sie möchten eine Klasse testen, die von einer Data Access Service- Klasse abhängt . Wenn diese Klasse mit einem Webdienst oder einer Datenbank kommuniziert, wird Ihr Komponententest in Ihrer Testumgebung nicht ausgeführt (und es wurde ein Integrationstest durchgeführt).

Lösung? Verwenden Sie eine Schnittstelle für Ihren Datenzugriffsdienst und verspotten Sie diese Schnittstelle, damit Sie Ihre Klasse als Einheit testen können.

Andererseits spielen WPF und Silverlight beim Binden überhaupt nicht mit Interfaces. Das ist eine ziemlich üble Falte.


2
hört hört! Schnittstellen wurden erfunden, um andere Probleme wie den Polymorphismus zu lösen. Für mich kommen sie jedoch zur Geltung, wenn sie ein Abhängigkeitsinjektionsmuster implementieren.
Andy

29

Schnittstellen sind das Rückgrat des (statischen) Polymorphismus! Auf die Schnittstelle kommt es an. Die Vererbung würde ohne Schnittstellen nicht funktionieren, da Unterklassen im Grunde die bereits implementierte Schnittstelle des übergeordneten Elements erben.

Wie oft benutzt du sie und warum machst du das?

Sehr oft. Alles, was steckbar sein muss, ist eine Schnittstelle in meinen Anwendungen. Häufig gibt es ansonsten nicht verwandte Klassen, die dasselbe Verhalten aufweisen müssen. Sie können solche Probleme nicht mit Vererbung lösen.

Benötigen Sie verschiedene Algorithmen, um Operationen mit denselben Daten auszuführen? Verwenden Sie eine Schnittstelle ( siehe Strategiemuster )!

Möchten Sie verschiedene Listenimplementierungen verwenden? Code gegen eine Schnittstelle und der Aufrufer muss sich nicht um die Implementierung kümmern!

Es wird seit langem als bewährte Methode (nicht nur in OOP) angesehen, Schnittstellen zu codieren, und zwar aus einem einzigen Grund: Es ist einfach, eine Implementierung zu ändern, wenn Sie feststellen, dass sie nicht Ihren Anforderungen entspricht. Es ist ziemlich umständlich, wenn Sie versuchen, dies nur durch Mehrfachvererbung zu erreichen, oder wenn Sie leere Klassen erstellen, um die erforderliche Schnittstelle bereitzustellen.


1
Noch nie von Polymorphie gehört, meinst du Polymorphie?
Steven Jeuris

1
Allerdings, wenn Microsoft Mehrfachvererbung überhaupt erlaubt hätte, hätte es keinen Grund für die Existenz von Schnittstellen gegeben
Pankaj Upadhyay

10
@ Pankaj Upadhyay: Mehrfachvererbung und Schnittstellen sind zwei verschiedene Paar Schuhe. Was ist, wenn Sie eine Schnittstelle aus zwei unabhängigen Klassen mit unterschiedlichem Verhalten benötigen? Sie können das nicht durch Mehrfachvererbung lösen. Sie MÜSSEN es trotzdem separat implementieren. Und dann benötigen Sie eine Beschreibung der Schnittstelle, um ein polymorphes Verhalten zu erzielen. Mehrfachvererbung ist in vielen Fällen eine Sackgasse und es ist zu einfach, sich früher oder später in den Fuß zu schießen.
Falcon

1
Vereinfachen wir es. Wenn meine Schnittstelle zwei Funktionen implementiert, Anzeige und Kommentar, und ich habe eine Klasse, die sie implementiert. Warum entferne ich dann nicht die Schnittstelle und nutze die Funktionen direkt. Was ich sage, ist, dass sie Ihnen nur die Namen der Funktionen zur Verfügung stellen, die implementiert werden müssen. Wenn man sich an diese Funktionen erinnern kann, warum dann eine Schnittstelle erstellen
Pankaj Upadhyay

9
@Pankaj, wenn das alles ist, wofür du das Interface brauchst, dann benutze es nicht. Sie verwenden eine Schnittstelle, wenn Sie ein Programm haben, das jeden Aspekt der Klasse ignorieren und über seinen Basistyp, dh die Schnittstelle, darauf zugreifen möchte. Sie müssen keine der Unterklassen kennen, nur, dass es sich um den Typ der Schnittstelle handelt. Als solches können Sie dann die implementierte Methode der Unterklasse über den Verweis auf die Schnittstelle des Objekts aufrufen. Dies sind grundlegende Vererbungs- und Design-Dinge. Ohne es könnten Sie auch C verwenden. Auch wenn Sie es nicht explizit verwenden, würde das Framework ohne es nicht funktionieren.
Jonathan Henson

12

Sie haben es wahrscheinlich foreachals ziemlich nützliches Iterationswerkzeug verwendet und gefunden. Wussten Sie, dass es eine Schnittstelle benötigt, um zu funktionieren, IEnumerable ?

Das ist sicherlich ein konkreter Fall, der auf die Nützlichkeit einer Schnittstelle verweist.


5
Tatsächlich benötigt foreach nicht IEnumerable: msdn.microsoft.com/en-us/library/9yb8xew9%28VS.80%29.aspx
Matt H

1
Ich habe das alles studiert, aber es ist, als würde man das Ohr mit der anderen Hand halten. Wenn Mehrfachvererbung zulässig gewesen wäre, wäre die Auswahl der Schnittstelle weit fortgeschritten.
Pankaj Upadhyay

2
Schnittstellen SIND Mehrfachvererbung, was oft vergessen wird. Sie erlauben jedoch keine mehrfache Vererbung von Verhalten und Zustand. Mixins oder Merkmale ermöglichen eine mehrfache Vererbung des Verhaltens, jedoch keinen gemeinsamen Zustand, der Probleme verursacht: en.wikipedia.org/wiki/Mixin
Matt H

@ Pankaj, offtopic, aber stört es dich, wenn ich frage, was deine Muttersprache ist? "Das Ohr mit der anderen Hand halten" ist eine großartige Redewendung und ich war neugierig, woher sie kommt.
Kevin

3
@Iceman. LOL .... Ich komme aus Indien. Und hier ist es eine verbreitete Redewendung, die widerspiegelt, wie man einfache Dinge auf schwierige Weise tut.
Pankaj Upadhyay

11

Schnittstellen dienen zur Codierung von Objekten wie ein Stecker zur Haushaltsverkabelung. Würden Sie Ihr Radio direkt an Ihre Hausverkabelung anlöten? Wie wäre es mit Ihrem Staubsauger? Natürlich nicht. Der Stecker und die Steckdose, in die er passt, bilden die "Schnittstelle" zwischen Ihrer Hausverkabelung und dem Gerät, das die Stromversorgung benötigt. Ihre Hausverkabelung muss nichts anderes über das Gerät wissen, als einen dreipoligen geerdeten Stecker zu verwenden und benötigt eine elektrische Spannung von 120VAC <= 15A. Umgekehrt erfordert das Gerät keine geheimen Kenntnisse über die Verkabelung Ihres Hauses. Es verfügt lediglich über eine oder mehrere dreipolige Steckdosen, die 120 VAC <= 15 A liefern.

Schnittstellen haben im Code eine sehr ähnliche Funktion. Ein Objekt kann deklarieren, dass eine bestimmte Variable, ein Parameter oder ein Rückgabetyp von einem Schnittstellentyp ist. Die Schnittstelle kann nicht direkt mit einem newSchlüsselwort instanziiert werden , aber mein Objekt kann die Implementierung dieser Schnittstelle erhalten oder finden, mit der es arbeiten muss. Sobald das Objekt seine Abhängigkeit hat, muss es nicht genau wissen, was diese Abhängigkeit ist, sondern es muss nur wissen, dass es Methoden X, Y und Z für die Abhängigkeit aufrufen kann. Implementierungen der Schnittstelle müssen nicht wissen, wie sie verwendet werden, sondern müssen nur wissen, dass von ihnen erwartet wird, dass sie die Methoden X, Y und Z mit bestimmten Signaturen versehen.

Indem Sie also mehrere Objekte hinter derselben Schnittstelle abstrahieren, stellen Sie jedem Benutzer von Objekten dieser Schnittstelle eine Reihe von Funktionen zur Verfügung. Sie müssen nicht wissen, dass das Objekt beispielsweise eine Liste, ein Dictionary, eine LinkedList, eine OrderedList oder was auch immer ist. Da Sie wissen, dass dies alles IEnumerables sind, können Sie die Methoden von IEnumerable verwenden, um jedes Element in diesen Auflistungen einzeln durchzugehen. Sie müssen nicht wissen, dass eine Ausgabeklasse ein ConsoleWriter, ein FileWriter, ein NetworkStreamWriter oder sogar ein MulticastWriter ist, der andere Arten von Writern akzeptiert. Alles, was Sie wissen müssen, ist, dass sie alle IWriter (oder was auch immer) sind, und daher haben sie eine "Write" -Methode, in die Sie einen String übergeben können, und dieser String wird ausgegeben.


7

Während es für den Programmierer (zumindest anfangs) ein Vergnügen ist, Mehrfachvererbung zu haben, ist dies eine fast triviale Auslassung, und Sie sollten sich (in den meisten Fällen) nicht auf Mehrfachvererbung verlassen. Die Gründe dafür sind komplex, aber wenn Sie wirklich etwas darüber lernen möchten, sollten Sie die Erfahrung aus den beiden bekanntesten (nach TIOBE-Index ) Programmiersprachen in Betracht ziehen , die es unterstützen: C ++ und Python (3. und 8. respektabel).

In Python wird die Mehrfachvererbung unterstützt, wird jedoch von Programmierern fast überall missverstanden. Wenn Sie feststellen, dass Sie wissen, wie es funktioniert, müssen Sie dieses Dokument zum Thema " Reihenfolge der Methodenauflösung" lesen und verstehen . Etwas anderes, was in Python passierte, ist, dass Schnittstellen irgendwie in die Sprache gelangen - Zope.Interfaces.

Für C ++ googeln Sie "Diamanthierarchie C ++" und sehen Sie sich die Hässlichkeit an, die Sie bedecken wird. C ++ - Profis können Mehrfachvererbung verwenden. Alle anderen spielen normalerweise nur herum, ohne zu wissen, was die Ergebnisse sein werden. Eine andere Sache, die zeigt, wie nützlich Schnittstellen sind, ist die Tatsache, dass eine Klasse in vielen Fällen das Verhalten ihrer Eltern vollständig außer Kraft setzen muss. In solchen Fällen ist die übergeordnete Implementierung nicht erforderlich und belastet die untergeordnete Klasse nur mit dem Speicher für die privaten Variablen der übergeordneten Klasse, was im C # -Alter möglicherweise keine Rolle spielt, aber wichtig ist, wenn Sie eingebettete Programmierung ausführen. Wenn Sie eine Schnittstelle verwenden, ist dieses Problem nicht vorhanden.

Zusammenfassend ist festzuhalten, dass Schnittstellen meiner Meinung nach ein wesentlicher Bestandteil von OOP sind, da sie einen Vertrag durchsetzen. Mehrfachvererbung ist in begrenzten Fällen nützlich und normalerweise nur für Leute, die wissen, wie man es benutzt. Wenn Sie also ein Anfänger sind, sind Sie derjenige, der durch das Fehlen einer Mehrfachvererbung behandelt wird - dies gibt Ihnen eine bessere Chance, keinen Fehler zu machen .

Historisch gesehen wurzelt die Idee für eine Benutzeroberfläche weit früher als die C # -Designspezifikationen von Microsoft. Die meisten Leute halten C # für ein Upgrade über Java (in den meisten Hinsichten) und raten, woher C # seine Schnittstellen hat - Java. Protocol ist ein älteres Wort für dasselbe Konzept und viel älter als .NET.

Update: Jetzt sehe ich, dass ich möglicherweise eine andere Frage beantwortet habe - warum Schnittstellen statt Mehrfachvererbung, aber dies schien die Antwort zu sein, die Sie gesucht haben. Außerdem sollte eine OO-Sprache mindestens eine der beiden haben, und die anderen Antworten haben Ihre ursprüngliche Frage abgedeckt.


6

Ich kann mir keinen sauberen, objektorientierten C # -Code ohne die Verwendung von Schnittstellen vorstellen. Sie verwenden sie immer dann, wenn Sie die Verfügbarkeit bestimmter Funktionen erzwingen möchten, ohne Klassen zu zwingen, von einer bestimmten Basisklasse zu erben, und dies ermöglicht Ihrem Code, die relevante Ebene der (geringen) Kopplung zu haben.

Ich bin nicht der Meinung, dass Mehrfachvererbung besser ist als Schnittstellen, noch bevor wir darüber streiten, dass Mehrfachvererbung mit eigenen Schmerzen verbunden ist. Schnittstellen sind ein grundlegendes Werkzeug, um Polymorphismus und Wiederverwendung von Code zu ermöglichen. Was braucht man mehr?


5

Ich persönlich liebe die abstrakte Klasse und benutze sie mehr als eine Schnittstelle. Der Hauptunterschied besteht in der Integration mit .NET-Schnittstellen wie IDisposable, IEnumerable usw. und mit COM-Interop. Darüber hinaus ist das Schreiben der Schnittstelle etwas einfacher als bei einer abstrakten Klasse, und eine Klasse kann mehr als eine Schnittstelle implementieren, während sie nur von einer Klasse erben kann.

Trotzdem finde ich, dass die meisten Dinge, für die ich eine Schnittstelle verwenden würde, von einer abstrakten Klasse besser bedient werden. Reine virtuelle Funktionen - abstrakte Funktionen - ermöglichen es Ihnen, einen Implementierer zu zwingen, eine Funktion zu definieren, ähnlich wie eine Schnittstelle einen Implementierer zwingt, alle ihre Mitglieder zu definieren.

Normalerweise verwenden Sie jedoch eine Schnittstelle, wenn Sie der Superklasse keinen bestimmten Entwurf auferlegen möchten, während Sie eine abstrakte Klasse verwenden würden, um einen wiederverwendbaren Entwurf zu erhalten, der bereits größtenteils implementiert ist.

Ich habe mit dem System.ComponentModel-Namespace umfangreiche Schnittstellen zum Schreiben von Plug-in-Umgebungen verwendet. Sie kommen ganz praktisch.


1
Sehr gut gesagt! Ich nehme an, mein Artikel über abstrakte Klassen wird Ihnen gefallen. Abstraktion ist alles .
Steven Jeuris

5

Ich kann sagen, ich beziehe mich darauf. Als ich anfing, etwas über OO und C # zu lernen, bekam ich auch keine Interfaces. Das ist okay. Wir müssen nur auf etwas stoßen, mit dem Sie den Komfort von Schnittstellen schätzen lernen.

Lassen Sie mich zwei Ansätze ausprobieren. Und verzeihen Sie mir die Verallgemeinerungen.

Versuchen Sie 1

Angenommen, Sie sprechen Englisch als Muttersprache. Sie reisen in ein anderes Land, in dem Englisch nicht die Muttersprache ist. Sie benötigen Hilfe. Sie brauchen jemanden, der Ihnen helfen kann.

Fragen Sie: "Hey, sind Sie in den Vereinigten Staaten geboren?" Das ist Vererbung.

Oder fragst du: "Hey, sprichst du Englisch?" Das ist Schnittstelle.

Wenn es Ihnen wichtig ist, was es tut, können Sie sich auf Schnittstellen verlassen. Wenn Sie sich für das interessieren, was ist, verlassen Sie sich auf Vererbung.

Es ist in Ordnung, sich auf die Vererbung zu verlassen. Wenn Sie jemanden brauchen, der Englisch spricht, Tee mag und Fußball mag, sollten Sie besser nach einem Briten fragen. :)

Versuchen Sie 2

Ok, lass uns ein anderes Beispiel versuchen.

Sie verwenden verschiedene Datenbanken und müssen abstrakte Klassen implementieren, um mit ihnen arbeiten zu können. Sie übergeben Ihre Klasse an eine Klasse des DB-Anbieters.

public abstract class SuperDatabaseHelper
{
   void Connect (string User, string Password)
}

public abstract class HiperDatabaseHelper
{
   void Connect (string Password, string User)
}

Mehrfachvererbung, sagen Sie? Versuchen Sie das mit dem obigen Fall. Das kannst du nicht. Der Compiler weiß nicht, welche Connect-Methode Sie aufrufen möchten.

interface ISuperDatabaseHelper
{
  void Connect (string User, string Password)
}

interface IHiperDatabaseHelper
{
   void Connect (string Password, string User)
}

Jetzt können wir - zumindest in C # - mit etwas arbeiten, mit dem wir Schnittstellen explizit implementieren können.

public class MyDatabaseHelper : ISuperDatabaseHelper, IHiperDatabaseHelper
{
   IHiperDataBaseHelper.Connect(string Password, string User)
   {
      //
   }

   ISuperDataBaseHelper.Connect(string User, string Password)
   {
      //
   }

}

Fazit

Die Beispiele sind nicht die besten, aber ich denke, es kommt darauf an.

Sie werden nur Schnittstellen "bekommen", wenn Sie das Bedürfnis danach haben. Bis sie denken Sie, dass sie nicht für Sie sind.


Der erste Versuch hat meine Stimme gegeben.
Osundblad

1
Ich verwende ab sofort die Analogie Amerikanisch vs. Englisch. Das ist fantastisch.
Bryan Boettcher

Einfacher erklärt! Fantastisch.
Aimal Khan

4

Es gibt zwei Hauptgründe:

  1. Fehlende Mehrfachvererbung. Sie können von einer Basisklasse erben und beliebig viele Schnittstellen implementieren. Dies ist die einzige Möglichkeit, Mehrfachvererbung in .NET durchzuführen.
  2. COM-Interoperabilität. Für alles, was von "älteren" Technologien verwendet werden muss, müssen Schnittstellen definiert werden.

Punkt 1 ist definitiv der Grund und der Grund, den Microsoft-Entwickler selbst entwickelt haben
Pankaj Upadhyay,

1
@Pankja Eigentlich haben sie die Interface-Idee von Java übernommen (wie ein guter Teil der Funktionen von C #).
Oliver Weiler

3

Durch die Verwendung von Schnittstellen bleibt ein System entkoppelt und kann leichter umgestaltet, geändert und neu bereitgestellt werden. Es ist ein sehr zentrales Konzept für die objektorientierte Orthodoxie, und ich habe es zum ersten Mal erfahren, als C ++ - Gurus "reine abstrakte Klassen" erstellten, die Schnittstellen ziemlich gleichwertig sind.


Die Entkopplung ist wichtig, da dadurch verschiedene Komponenten eines Systems voneinander unabhängig bleiben. Selbst große Änderungen an einer Komponente wirken sich nicht auf andere Komponenten aus. Stellen Sie sich Netzstecker als Schnittstelle zu Ihrem Energieversorgungsunternehmen vor (unter Angabe der Spannung sowie der physischen Anschlüsse und des Formats des Steckers). Dank dieser Schnittstelle kann das Versorgungsunternehmen die Art und Weise, in der es Strom erzeugt, vollständig ändern (z. B. mithilfe von Solartechnologie), aber keines der Geräte merkt, dass sich etwas ändert, geschweige denn.
Miraculixx

3

Schnittstellen an sich sind nicht sehr nützlich. Bei der Implementierung durch konkrete Klassen sehen Sie jedoch, dass Sie die Flexibilität haben, eine oder mehrere Implementierungen vorzunehmen. Der Vorteil ist, dass das Objekt, das die Schnittstelle verwendet, nicht wissen muss, wie die Details der tatsächlichen Implementierung verlaufen - das nennt man Kapselung.


2

Sie werden hauptsächlich für die Wiederverwendbarkeit von Code verwendet. Wenn Sie mit der Schnittstelle codieren, können Sie eine andere Klasse verwenden, die von dieser Schnittstelle erbt und nicht alles aufteilt.

Außerdem sind sie in Webservices sehr nützlich, bei denen Sie dem Client mitteilen möchten, was eine Klasse tut (damit sie sie verwenden kann), ihnen aber nicht den tatsächlichen Code geben möchten.


2

Als junger Programmierer / Entwickler erkennen Sie beim Erlernen von C # möglicherweise nicht den Nutzen der Benutzeroberfläche, da Sie Ihre Codes möglicherweise mithilfe Ihrer Klassen schreiben und der Code problemlos funktioniert. Im realen Szenario erfordert das Erstellen einer skalierbaren, robusten und wartbaren Anwendung jedoch die Verwendung von Einige Architekturen und Muster, die nur über die Schnittstelle möglich sind, befinden sich beispielsweise in Abhängigkeitsinjektion.


1

Eine echte Implementierung:

Sie können ein Objekt als Schnittstellentyp umwandeln:

IHelper h = (IHelper)o;
h.HelperMethod();

Sie können eine Liste einer Schnittstelle erstellen

List<IHelper> HelperList = new List<IHelper>();

Mit diesen Objekten können Sie auf eine der Schnittstellenmethoden oder -eigenschaften zugreifen. Auf diese Weise können Sie eine Schnittstelle für Ihren Teil eines Programms definieren. Und bauen Sie die Logik darauf auf. Dann kann eine andere Person Ihre Schnittstelle in ihre Geschäftsobjekte implementieren. Wenn sich die BOs ändern, können sie die Logik für die Schnittstellenkomponenten ändern und erfordern keine Änderung der Logik für Ihr Teil.


0

Schnittstellen ermöglichen Modularität im Plug-in-Stil, indem sie Klassen einen Mechanismus bieten, mit dem sie bestimmte Arten von Nachrichten, die Ihr System übermittelt, verstehen (und abonnieren) können. Ich werde näher darauf eingehen.

In Ihrer Anwendung legen Sie fest, dass jedes Mal, wenn ein Formular geladen oder neu geladen wird, alle darin enthaltenen Elemente gelöscht werden sollen. Sie definieren eine IClearSchnittstelle, die implementiert wird Clear. Darüber hinaus entscheiden Sie, dass das Formular versuchen soll, seinen Status beizubehalten, wenn der Benutzer auf die Schaltfläche Speichern klickt. Somit ISaveerhält alles, was daran festhält, eine Nachricht, um seinen Zustand beizubehalten . In der Praxis verarbeiten die meisten Schnittstellen natürlich mehrere Nachrichten.

Das Besondere an Schnittstellen ist, dass ein gemeinsames Verhalten ohne Vererbung erreicht werden kann. Die Klasse, die eine bestimmte Schnittstelle implementiert, versteht einfach, wie sie sich verhält, wenn ein Befehl ausgegeben wird (eine Befehlsnachricht) oder wie sie auf Abfragen reagiert (eine Abfragenachricht). Im Wesentlichen verstehen die Klassen in Ihrer Anwendung die Nachrichten, die Ihre Anwendung bereitstellt. Dies erleichtert den Aufbau eines modularen Systems, in das Dinge eingesteckt werden können.

In den meisten Sprachen gibt es Mechanismen (wie LINQ ) zum Abfragen von Dingen, die sich an eine Schnittstelle halten. Dies hilft Ihnen normalerweise dabei, die bedingte Logik zu eliminieren, da Sie nicht verschiedenen Dingen (die nicht aus derselben Vererbungskette stammen müssen) mitteilen müssen, wie sie sich ähnlich verhalten sollen (gemäß einer bestimmten Nachricht). Stattdessen sammeln Sie alles, was eine bestimmte Nachricht versteht (und halten sich an eine Schnittstelle), und veröffentlichen die Nachricht.

Zum Beispiel könnten Sie ersetzen ...

Me.PublishDate.Clear()
Me.Subject.Clear()
Me.Body.Clear()

...mit:

For Each ctl As IClear In Me.Controls.OfType(Of IClear)()
    ctl.Clear()
Next

Was sich im Grunde nach Folgendem anhört:

Höre, höre! Würden alle, die Clearing verstehen, bitte Clearjetzt!

Auf diese Weise können wir programmgesteuert vermeiden, dass jedes einzelne Element aufgefordert wird, sich selbst zu löschen. Und wenn in Zukunft löschbare Elemente hinzugefügt werden, reagieren sie einfach ohne zusätzlichen Code.


0

Das Folgende ist Pseudocode:

class MyClass{

    private MyInterface = new MyInterfaceImplementationB();

    // Code using Thingy 

}

interface MyInterface{

    myMethod();

}

class MyInterfaceImplementationA{ myMethod(){ // method implementation A } }

class MyInterfaceImplementationB{ myMethod(){ // method implementation B } }

class MyInterfaceImplementationC{ myMethod(){ // method implementation C } }

Die letzten Klassen können völlig unterschiedliche Implementierungen sein.

Sofern keine Mehrfachvererbung möglich ist, wird durch die Vererbung die Implementierung der übergeordneten Klasse erzwungen, wodurch die Dinge starrer werden. Die Programmierung anhand von Schnittstellen hingegen kann dazu führen, dass Ihr Code oder ein Framework äußerst flexibel ist. Wenn Sie jemals auf einen Fall stoßen, in dem Sie sich gewünscht haben, Klassen in einer Vererbungskette zu tauschen, werden Sie verstehen, warum.

Beispielsweise könnte ein Framework, das einen Reader bereitstellt, der ursprünglich zum Lesen von Daten von der Festplatte vorgesehen war, erneut implementiert werden, um etwas in der gleichen Art, jedoch auf eine völlig andere Art und Weise zu tun. Wie zum Beispiel Morse-Code interpretieren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.