Ich benutze nur selten Schnittstellen und finde sie in anderen Codes häufig.
Außerdem erstelle ich in meinem Code selten Unter- und Superklassen (während ich meine eigenen Klassen erstelle).
- Ist es eine schlechte Sache?
- Würden Sie vorschlagen, diesen Stil zu ändern?
- Hat dieser Stil irgendwelche Nebenwirkungen?
- Liegt es daran, dass ich noch keine großen Projekte bearbeitet habe?
programming-practices
coding-style
interfaces
jineesh joseph
quelle
quelle
Antworten:
Es gibt mehrere Gründe, warum Sie Schnittstellen verwenden möchten:
http://msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80).aspx
Schnittstellen sind wie alles andere in der Programmierung. Wenn du sie nicht brauchst, benutze sie nicht. Ich habe gesehen, dass sie aus Gründen des Stils ausgiebig verwendet werden, aber wenn Sie nicht die speziellen Eigenschaften und Fähigkeiten benötigen, die eine Schnittstelle bietet, sehe ich nicht den Vorteil, sie "nur weil" zu verwenden.
quelle
Sowohl die Klassenvererbung als auch die Schnittstellen haben ihren Platz. Vererbung bedeutet "ist ein", während eine Schnittstelle einen Vertrag bereitstellt, der definiert, wie sich etwas "verhält".
Ich würde sagen, dass die häufigere Verwendung von Schnittstellen überhaupt keine schlechte Praxis ist. Ich lese gerade "Effective C # - 50 Specific Ways to Improve Your C #" von Bill Wagner. In Artikel 22 heißt es, und ich zitiere "Definieren und Implementieren von Schnittstellen der Vererbung vorziehen".
Im Allgemeinen verwende ich Basisklassen, wenn ich eine bestimmte Implementierung des gemeinsamen Verhaltens zwischen konzeptionell verwandten Typen definieren muss. Häufiger benutze ich Schnittstellen. Eigentlich beginne ich normalerweise damit, eine Schnittstelle für eine Klasse zu definieren, wenn ich damit beginne, eine zu erstellen. Auch wenn ich die Schnittstelle am Ende nicht kompiliere, finde ich, dass es hilfreich ist, zunächst die öffentliche API der zu definieren Klasse von Anfang an. Wenn ich feststelle, dass ich mehrere Klassen habe, die beide die Schnittstelle implementieren, und die Implementierungslogik identisch ist, werde ich mich nur dann fragen, ob es sinnvoll wäre, eine gemeinsame Basisklasse zwischen den Typen zu implementieren.
Ein paar Zitate aus Bill Wagners Buch ...
Alle abgeleiteten Klassen berücksichtigen dieses Verhalten sofort. Durch das Hinzufügen eines Members zu einer Schnittstelle werden alle Klassen getrennt, die diese Schnittstelle implementieren. Sie enthalten die neue Methode nicht und werden nicht mehr kompiliert. Jeder Implementierer muss diesen Typ aktualisieren, um das neue Mitglied aufzunehmen. Die Wahl zwischen einer abstrakten Basisklasse und einer Schnittstelle ist eine Frage, wie Sie Ihre Abstraktionen im Laufe der Zeit am besten unterstützen können. Schnittstellen sind fest: Sie geben eine Schnittstelle als Vertrag für eine Reihe von Funktionen frei, die jeder Typ implementieren kann. Basisklassen können im Laufe der Zeit erweitert werden. Diese Erweiterungen werden Teil jeder abgeleiteten Klasse. Die beiden Modelle können gemischt werden, um den Implementierungscode wiederzuverwenden und gleichzeitig mehrere Schnittstellen zu unterstützen. " Sie enthalten die neue Methode nicht und werden nicht mehr kompiliert. Jeder Implementierer muss diesen Typ aktualisieren, um das neue Mitglied aufzunehmen. Die Wahl zwischen einer abstrakten Basisklasse und einer Schnittstelle ist eine Frage, wie Sie Ihre Abstraktionen im Laufe der Zeit am besten unterstützen können. Schnittstellen sind fest: Sie geben eine Schnittstelle als Vertrag für eine Reihe von Funktionen frei, die jeder Typ implementieren kann. Basisklassen können im Laufe der Zeit erweitert werden. Diese Erweiterungen werden Teil jeder abgeleiteten Klasse. Die beiden Modelle können gemischt werden, um den Implementierungscode wiederzuverwenden und gleichzeitig mehrere Schnittstellen zu unterstützen. " Sie enthalten die neue Methode nicht und werden nicht mehr kompiliert. Jeder Implementierer muss diesen Typ aktualisieren, um das neue Mitglied aufzunehmen. Die Wahl zwischen einer abstrakten Basisklasse und einer Schnittstelle ist eine Frage, wie Sie Ihre Abstraktionen im Laufe der Zeit am besten unterstützen können. Schnittstellen sind fest: Sie geben eine Schnittstelle als Vertrag für eine Reihe von Funktionen frei, die jeder Typ implementieren kann. Basisklassen können im Laufe der Zeit erweitert werden. Diese Erweiterungen werden Teil jeder abgeleiteten Klasse. Die beiden Modelle können gemischt werden, um den Implementierungscode wiederzuverwenden und gleichzeitig mehrere Schnittstellen zu unterstützen. " Sie geben eine Schnittstelle als Vertrag für eine Reihe von Funktionen frei, die jeder Typ implementieren kann. Basisklassen können im Laufe der Zeit erweitert werden. Diese Erweiterungen werden Teil jeder abgeleiteten Klasse. Die beiden Modelle können gemischt werden, um den Implementierungscode wiederzuverwenden und gleichzeitig mehrere Schnittstellen zu unterstützen. " Sie geben eine Schnittstelle als Vertrag für eine Reihe von Funktionen frei, die jeder Typ implementieren kann. Basisklassen können im Laufe der Zeit erweitert werden. Diese Erweiterungen werden Teil jeder abgeleiteten Klasse. Die beiden Modelle können gemischt werden, um den Implementierungscode wiederzuverwenden und gleichzeitig mehrere Schnittstellen zu unterstützen. "
"Coding Interfaces bieten anderen Entwicklern eine größere Flexibilität als das Codieren in Basisklassentypen."
"Die Verwendung von Schnittstellen zum Definieren von APIs für eine Klasse bietet eine größere Flexibilität."
"Wenn Ihr Typ Eigenschaften als Klassentypen verfügbar macht, macht er die gesamte Schnittstelle für diese Klasse verfügbar. Mithilfe von Schnittstellen können Sie festlegen, dass nur die Methoden und Eigenschaften verfügbar gemacht werden, die Clients verwenden sollen."
"Basisklassen beschreiben und implementieren gemeinsames Verhalten über verwandte konkrete Typen hinweg. Schnittstellen beschreiben atomare Funktionalitätsteile, die nicht verwandte konkrete Typen implementieren können. Beide haben ihren Platz. Klassen definieren die Typen, die Sie erstellen. Schnittstellen beschreiben das Verhalten dieser Typen als Funktionalitätsteile. Wenn Sie die Unterschiede verstehen, werden Sie ausdrucksstärkere Designs erstellen, die angesichts von Änderungen widerstandsfähiger sind. Verwenden Sie Klassenhierarchien, um verwandte Typen zu definieren.
quelle
Eine Sache , die nicht erwähnt wird getestet: in allen C # spöttisch-Bibliotheken, sowie einige für Java - Klassen können nicht verspottet werden , wenn sie eine Schnittstelle implementieren. Dies führt dazu, dass viele Projekte den Agile / TDD-Praktiken folgen und jeder Klasse eine eigene Schnittstelle zugewiesen wird.
Einige Leute halten diese bewährte Methode für "weniger Kopplung", aber ich bin anderer Meinung - ich denke, es ist nur eine Umgehung eines Sprachmangels.
Ich denke, dass Interfaces am besten verwendet werden, wenn Sie zwei oder mehr Klassen haben, die abstrakt gesehen dasselbe tun, aber auf unterschiedliche Weise.
Das .Net-Framework verfügt beispielsweise über mehrere Klassen, in denen Listen mit Inhalten gespeichert werden , die jedoch alle auf unterschiedliche Weise gespeichert werden. Es ist daher sinnvoll, eine abstrakte
IList<T>
Schnittstelle zu haben , die mit verschiedenen Methoden implementiert werden kann.Sie sollten es auch verwenden, wenn 2+ Klassen austauschbar oder in Zukunft austauschbar sein sollen. Wenn in Zukunft eine neue Methode zum Speichern von Listen auf den Markt kommt, müssten
AwesomeList<T>
Sie, wenn Sie denIList<T>
gesamten Code verwendenAwesomeList<T>
, nur ein paar Dutzend Zeilen anstatt ein paar Hunderttausend Zeilen ändern.quelle
Das Hauptergebnis, wenn Vererbung und Schnittstellen nicht verwendet werden, wenn sie angemessen sind, ist eine enge Kopplung . Es kann etwas schwierig sein, dies zu erkennen, aber normalerweise ist das offensichtlichste Symptom, wenn Sie eine Änderung vornehmen. Sie müssen häufig eine ganze Reihe anderer Dateien durchgehen, um Änderungen an einem Ripple-Effekt vorzunehmen.
quelle
Nein, das ist überhaupt nicht schlecht. Explizite Schnittstellen sollten genau dann verwendet werden, wenn zwei Klassen mit einer gemeinsamen Schnittstelle zur Laufzeit austauschbar sein müssen. Wenn sie nicht austauschbar sein müssen, lassen Sie sie nicht erben. So einfach ist das. Vererbung ist zerbrechlich und sollte nach Möglichkeit vermieden werden. Wenn Sie dies vermeiden oder stattdessen Generika verwenden können, tun Sie dies.
Das Problem ist, dass in Sprachen wie C # und Java mit Generika zur schwachen Kompilierungszeit möglicherweise DRY verletzt wird, da es keine Möglichkeit gibt, eine Methode zu schreiben, die mit mehr als einer Klasse umgehen kann, es sei denn, alle Klassen erben von derselben Basis. C # 4
dynamic
kann damit umgehen.Die Sache ist, Vererbung ist wie globale Variablen - wenn Sie es hinzufügen und Ihr Code davon abhängt, hilft Gott Ihnen, es wegzunehmen. Sie können es jedoch jederzeit hinzufügen, und Sie können es sogar hinzufügen, ohne die Basisklasse zu ändern, indem Sie eine Art Wrapper verwenden.
quelle
Ja, die Verwendung von Schnittstellen ist wahrscheinlich nicht (oder zu selten) eine schlechte Sache. Interfaces (im abstrakten Sinne und das C # / Java-Sprachkonstrukt ist eine ziemlich gute Annäherung an diesen abstrakten Sinn) definieren explizite Interaktionspunkte zwischen Systemen und Subsystemen. Dies trägt zur Reduzierung der Kopplung bei und macht das System wartungsfreundlicher. Wie bei allem, was die Wartbarkeit verbessert, wird es umso wichtiger, je größer ein System ist.
quelle
Ich habe seit Jahren keine Schnittstelle mehr benutzt. Das liegt natürlich daran, dass ich seit Jahren fast ausschließlich in Erlang programmiere und das gesamte Konzept einer Schnittstelle einfach nicht existiert. (Das nächste, was du bekommst, ist ein "Verhalten" und das ist nicht wirklich dasselbe, es sei denn, du blinzelst wirklich hart und siehst sie aus dem Augenwinkel an.)
Ihre Frage ist also wirklich paradigmenabhängig (in diesem Fall OOP) und außerdem sehr sprachabhängig (es gibt OOP-Sprachen ohne Schnittstellen).
quelle
Wenn Sie über die Verwendung von Java sprechen, liegt ein Grund für die Verwendung von Schnittstellen darin, dass sie die Verwendung von Proxy-Objekten ohne Codegenerierungsbibliotheken ermöglichen. Dies kann ein wesentlicher Vorteil sein, wenn Sie mit einem komplexen Framework wie Spring arbeiten. Darüber hinaus sind für einige Funktionen Schnittstellen erforderlich : RMI ist das klassische Beispiel dafür, da Sie die von Ihnen bereitgestellten Funktionen in Form von Schnittstellen (die von geerbt werden
java.rmi.Remote
) beschreiben müssen, unabhängig davon, wie Sie sie implementieren.quelle
Die Dinge ändern sich ( MS Moles ), aber der Hauptgrund, warum ich denke, dass es gut ist, fast ausschließlich auf Schnittstellen zu programmieren, ist, dass sie leicht zu verspotten sind und sich auf natürliche Weise in eine IoC-Architektur einfügen.
IMO sollten Sie immer nur mit Schnittstellen arbeiten, oder, wo immer möglich, völlig dumme DAOs. Wenn Sie in diese Denkweise geraten und eine Bibliothek verwenden, die sich nicht über Schnittstellen ausstellt und alles über konkrete Objekte erledigt, muss ich ehrlich sein, dann fühlt sich alles ein bisschen klobig an.
quelle
Bei alten Modeprojekten werden Schnittstellen verwendet, um Zirkelverweise zu vermeiden, da Zirkelverweise auf lange Sicht ein großes Wartungsproblem darstellen können.
Schlecht:
Nicht schlecht:
Normalerweise werden A, B, PartOfClassB_AccessedByA mit separaten Dateien implementiert.
quelle
Durch die schnittstellenbasierte Programmierung lässt sich Code flexibler und einfacher testen. Die Implementierungsklassen können geändert werden, ohne den Client-Code zu berühren [Flexibilität]. Beim Testen von Code kann man die eigentliche oInterface-basierte Programmierung ersetzen, um den Code flexibler und einfacher zu testen. Die Implementierungsklassen können geändert werden, ohne den Client-Code zu berühren [Flexibilität]. Beim Testen von Code kann man das tatsächliche Objekt durch Scheinobjekte [Testbarkeit] .bject durch Scheinobjekte [Testbarkeit] ersetzen.
quelle