it-swarm.com.de

Ist es eine gute Praxis, die Schnittstelle in derselben Datei wie die Basisklasse zu deklarieren?

Um austauschbar und testbar zu sein, müssen Dienste mit Logik normalerweise eine Schnittstelle haben, z.

public class FooService: IFooService 
{ ... }

In Bezug auf das Design stimme ich dem zu, aber eines der Dinge, die mich an diesem Ansatz stören, ist, dass Sie für einen Dienst zwei Dinge deklarieren müssen (die Klasse und die Schnittstelle) und in unserem Team normalerweise zwei Dateien (eine für die Klasse und eine für die Schnittstelle). Ein weiteres Problem ist die Schwierigkeit bei der Navigation, da die Verwendung von "Zur Definition gehen" in IDE (VS2010)) auf die Schnittstelle verweist (da andere Klassen auf die Schnittstelle verweisen) und nicht auf die eigentliche Klasse.

Ich dachte, dass das Schreiben von IFooService in derselben Datei wie FooService die oben genannte Verrücktheit verringern würde. Immerhin sind IFooService und FooService sehr verwandt. Ist das eine gute Praxis? Gibt es einen guten Grund, warum sich IFooService in einer eigenen Datei befinden muss?

29
Louis Rhys

Es muss nicht in einer eigenen Datei sein, aber Ihr Team sollte sich für einen Standard entscheiden und sich daran halten.

Sie haben auch Recht, dass "Zur Definition gehen" Sie zur Schnittstelle führt. Wenn Sie jedoch Resharper installiert haben, können Sie mit nur einem Klick eine Liste der von dieser Schnittstelle abgeleiteten Klassen/Schnittstellen öffnen es ist keine große Sache. Deshalb behalte ich die Schnittstelle in einer separaten Datei.

24
Scott Whitlock

Ich denke, Sie sollten sie separate Dateien aufbewahren. Wie Sie sagten, besteht die Idee darin, testbar und austauschbar zu bleiben. Indem Sie die Schnittstelle in dieselbe Datei wie Ihre Implementierung einfügen, ordnen Sie die Schnittstelle der spezifischen Implementierung zu. Wenn Sie sich entscheiden, ein Scheinobjekt oder eine andere Implementierung zu erstellen, ist die Schnittstelle nicht logisch von FooService getrennt.

15
Brad S

Laut SOLID sollten Sie die Schnittstelle nicht nur erstellen und nicht nur in einer anderen Datei, sondern auch in einer anderen Assembly.

Warum? Da jede Änderung an einer Quelldatei, die in eine Assembly kompiliert wird, eine Neukompilierung der Assembly erfordert und jede Änderung an einer Assembly die Neukompilierung einer abhängigen Assembly erfordert. Wenn Ihr Ziel, basierend auf SOLID, darin besteht, eine Implementierung A durch eine Implementierung B zu ersetzen, während die von der Schnittstelle abhängige Klasse C den Unterschied nicht kennen muss, müssen Sie sicherstellen, dass die Assembly mit I übereinstimmt Darin ändert sich nichts und schützt so die Nutzung.

"Aber es ist nur eine Neukompilierung", höre ich Sie protestieren. Nun, das mag sein, aber in Ihrer Smartphone-App, was die Datenbandbreite Ihrer Benutzer schont. eine geänderte Binärdatei herunterladen oder diese Binärdatei und fünf andere mit davon abhängigem Code herunterladen? Nicht jedes Programm ist so geschrieben, dass es von Desktop-Computern in einem LAN verwendet wird. Selbst in diesem Fall, in dem Bandbreite und Speicher billig sind, können kleinere Patch-Releases einen Wert haben, da sie über Active Directory oder ähnliche Domänenverwaltungsebenen trivial in das gesamte LAN übertragen werden können. Ihre Benutzer warten nur einige Sekunden, bis sie beim nächsten Anmelden angewendet werden, anstatt einige Minuten, bis das Ganze neu installiert wurde. Ganz zu schweigen davon, dass je weniger Baugruppen beim Erstellen eines Projekts neu kompiliert werden müssen, desto schneller wird es erstellt, was Sie produktiver macht, da Sie weniger Zeit damit verbringen, darauf zu warten, dass 50 Baugruppen für jede von Ihnen vorgenommene Änderung erstellt werden.

Nun zum Haftungsausschluss: Dies ist nicht immer möglich oder machbar. Der einfachste Weg, dies zu tun, besteht darin, ein zentrales "Schnittstellen" -Projekt zu erstellen. Dies hat seine eigenen Nachteile; Code wird weniger wiederverwendbar, da auf das Schnittstellenprojekt UND das Implementierungsprojekt in anderen Apps verwiesen werden muss, die die Persistenzschicht oder andere Schlüsselkomponenten Ihrer App wiederverwenden. Sie können dieses Problem lösen, indem Sie die Schnittstellen in eng gekoppelte Baugruppen aufteilen. Dann haben Sie jedoch mehr Projekte in Ihrer App, was einen vollständigen Build sehr schmerzhaft macht. Der Schlüssel ist das Gleichgewicht und die Beibehaltung des lose gekoppelten Designs. Normalerweise können Sie Dateien nach Bedarf verschieben. Wenn Sie also feststellen, dass eine Klasse viele Änderungen benötigt oder regelmäßig neue Implementierungen einer Schnittstelle erforderlich sind (möglicherweise, um mit neu unterstützten Versionen anderer Software oder Dateitypen usw. zu kommunizieren) ) Sie können es von seiner Schnittstelle trennen und die Nutzung vor Kenntnis dieser Änderungen schützen.

10
KeithS

Warum ist es unangenehm, separate Dateien zu haben? Für mich ist es viel ordentlicher und sauberer. Es ist üblich, einen Unterordner mit dem Namen "Interfaces" zu erstellen und Ihre IFooServer.cs-Dateien dort zu speichern, wenn Sie weniger Dateien in Ihrem Projektmappen-Explorer anzeigen möchten.

Der Grund, warum die Schnittstelle in einer eigenen Datei definiert ist, ist der gleiche, aus dem Klassen normalerweise in einer eigenen Datei definiert werden: Die Projektverwaltung ist einfacher, wenn Ihre logische Struktur und Dateistruktur identisch sind, sodass Sie immer wissen, welche Datei eine bestimmte Klasse definiert ist Dies kann Ihnen das Leben beim Debuggen erleichtern (Ausnahmestapel-Traces geben Ihnen normalerweise Datei- und Zeilennummern) oder beim Zusammenführen von Quellcode in einem Quellcodeverwaltungs-Repository.

Es wird häufig empfohlen, dass Ihre Codedateien nur eine einzige Klasse oder eine einzelne Schnittstelle enthalten. Diese Codierungspraktiken sind jedoch ein Mittel zum Zweck - um Ihren Code besser zu strukturieren und die Arbeit mit ihm zu vereinfachen. Wenn Sie und Ihr Team es einfacher finden, mit ihnen zu arbeiten, wenn die Klassen mit ihren Schnittstellen zusammengehalten werden, tun Sie dies auf jeden Fall.

Persönlich bevorzuge ich es, die Schnittstelle und die Klasse in derselben Datei zu haben, wenn es nur eine Klasse gibt, die die Schnittstelle implementiert, wie in Ihrem Fall.

In Bezug auf die Probleme, die Sie mit der Navigation haben, kann ich ReSharper sehr empfehlen. Es enthält einige äußerst nützliche Verknüpfungen, mit denen Sie direkt zur Methode springen können, die eine bestimmte Schnittstellenmethode implementiert.

6
Pete

Es gibt viele Fälle, in denen Sie möchten, dass sich Ihre Schnittstelle nicht nur in einer separaten Datei zur Klasse befindet, sondern sogar in einer separate Baugruppe insgesamt.

Beispielsweise kann eine WCF-Servicevertragsschnittstelle sowohl vom Client als auch vom Service gemeinsam genutzt sein, wenn Sie die Kontrolle über beide Enden der Leitung haben. Wenn Sie die Schnittstelle in eine eigene Assembly verschieben, hat sie weniger eigene Assembly-Abhängigkeiten. Dies erleichtert dem Kunden das Konsumieren erheblich und löst die Kopplung mit seiner Implementierung.

3
StuartLC

Schnittstellen gehören ihren Kunden und nicht ihren Implementierungen, wie in Agile Principles, Practices and Patterns von Robert C. Martin definiert. Die Kombination von Schnittstelle und Implementierung an derselben Stelle verstößt daher gegen das Prinzip.

Der Client-Code hängt von der Schnittstelle ab. Dies ermöglicht die Kompilierung und Bereitstellung des Client-Codes und der Schnittstelle ohne die Implementierung. Dann können verschiedene Implementierungen wie Plugins zum Client-Code funktionieren.

UPDATE: Dies ist hier kein rein agiles Prinzip. Die Viererbande in Design Patterns aus dem Jahr 1994 spricht bereits von Clients, die sich an Schnittstellen halten und auf Schnittstellen programmieren. Ihre Ansicht ist ähnlich.

2
Patkos Csaba

Es ist selten, wenn überhaupt, sinnvoll, eine einzige Implementierung einer Schnittstelle zu haben1. Wenn Sie eine öffentliche Schnittstelle und eine öffentliche Klasse, die diese Schnittstelle implementieren, in dieselbe Datei einfügen, besteht eine gute Chance, dass Sie keine Schnittstelle benötigen.

Wenn die Klasse, die Sie zusammen mit der Schnittstelle suchen, abstract ist und Sie wissen, dass alle Implementierungen Ihrer Schnittstelle diese abstrakte Klasse erben sollten, ist es sinnvoll, die beiden in derselben Datei zu lokalisieren. Sie sollten Ihre Entscheidung, eine Schnittstelle zu verwenden, immer noch überprüfen: Fragen Sie sich, ob eine abstrakte Klasse für sich allein in Ordnung wäre, und lassen Sie die Schnittstelle fallen, wenn die Antwort positiv ist.

Im Allgemeinen sollten Sie sich jedoch an die Strategie "Eine öffentliche Klasse/Schnittstelle entspricht einer Datei" halten: Sie ist einfach zu befolgen und erleichtert die Navigation in Ihrem Quellbaum.


1
2
dasblinkenlight

Wenn Sie eine Klasse und eine Schnittstelle in dieselbe Datei einfügen, sind der Verwendung beider Klassen keine Grenzen gesetzt. Eine Schnittstelle kann weiterhin auf die gleiche Weise für Mocks usw. verwendet werden, selbst wenn sie sich in derselben Datei befindet wie eine Klasse, die sie implementiert. Die Frage könnte nur als organisatorische Bequemlichkeit wahrgenommen werden. In diesem Fall würde ich sagen, tun Sie, was Ihnen das Leben leichter macht!

Natürlich könnte man argumentieren, dass die beiden in derselben Datei dazu führen könnten, dass Unachtsame sie als programmgesteuerter als sie tatsächlich betrachten, was ein Risiko darstellt.

Persönlich wäre ich nicht allzu besorgt, wenn ich auf eine Codebasis stoßen würde, die eine Konvention über die andere verwendet.

0
Holf

Ich persönlich mag das "Ich" vor einer Schnittstelle nicht. Als Benutzer eines solchen Typs möchte ich nicht sehen, dass dies eine Schnittstelle ist oder nicht. Der Typ ist das Interessante. In Bezug auf Abhängigkeiten ist Ihr FooService EINE mögliche Implementierung von IFooService. Die Schnittstelle sollte sich in der Nähe des Ortes befinden, an dem sie verwendet wird. Andererseits sollte sich die Implementierung an einem Ort befinden, an dem sie leicht geändert werden kann, ohne den Client zu beeinträchtigen. Daher würde ich normalerweise zwei Dateien bevorzugen.

0
ollins

Die Codierung von Schnittstellen kann schlecht sein, wird in der Tat als Anti-Muster für bestimmte Kontexte behandelt und ist kein Gesetz. Normalerweise ist ein gutes Beispiel für die Codierung von Schnittstellen-Anti-Patterns, wenn Sie eine Schnittstelle haben, die nur eine Implementierung in Ihrer Anwendung hat. Eine andere Möglichkeit wäre, wenn die Schnittstellendatei so störend wird, dass Sie ihre Deklaration in der Datei der implementierten Klasse ausblenden müssen.

0
Shivan Dragon