Verwendung expliziter Schnittstellen, um die Programmierung gegen eine Schnittstelle zu gewährleisten

8

Ich habe Argumente für die Verwendung expliziter Schnittstellen als eine Methode zum Sperren einer Klassenverwendung für diese Schnittstelle gesehen. Das Argument scheint zu sein, dass man, indem man andere zur Programmierung der Schnittstelle zwingt, eine bessere Entkopplung der Klassen sicherstellen und ein einfacheres Testen ermöglichen kann.

Beispiel:

%Vor%

Und das Messer-Objekt zu verwenden:

%Vor%

Würden Sie diese Methode der Schnittstellenimplementierung empfehlen? Warum oder warum nicht?

BEARBEITEN: Auch wenn ich eine explizite Schnittstelle verwende, würde das folgende NICHT funktionieren.

%Vor%     
chills42 07.10.2008, 14:51
quelle

11 Antworten

4

Um GoF Kapitel 1 zu zitieren:

  • "Programmiere eine Schnittstelle, keine Implementierung".
  • "Favor-Objekt-Komposition über Klassenvererbung".

Da C # keine Mehrfachvererbung hat, sind die Objektkomposition und die Programmierung für Schnittstellen der richtige Weg.

ETA: Und du solltest sowieso niemals Mehrfachvererbung benutzen, aber das ist ein anderes Thema.: -)

ETA2: Ich bin mir über die explizite Schnittstelle nicht so sicher. Das scheint nicht konstruktiv zu sein. Warum sollte ich ein Messer haben wollen, das nur schneidet () wenn es als ICut instanziiert wird?

    
erlando 07.10.2008, 15:02
quelle
3

Ich habe es nur in Szenarien verwendet, in denen ich den Zugriff auf bestimmte Methoden einschränken möchte.

%Vor%

Jetzt kann Foo Nachrichten mit _messageWriter in das Nachrichtenprotokoll schreiben, aber Clients können nur lesen. Dies ist besonders vorteilhaft in einem Szenario, in dem Ihre Klassen ComVisible sind. Ihr Client kann nicht in den Writer-Typ umwandeln und die Informationen im Nachrichtenprotokoll ändern.

    
ilitirit 07.10.2008 15:21
quelle
2

Ja. Und nicht nur zum Testen. Es ist sinnvoll, gewöhnliches Verhalten in eine Schnittstelle (oder eine abstrakte Klasse) einzuordnen; Auf diese Weise können Sie Polymorphie nutzen.

%Vor%

Factory könnte eine Art scharfes Gerät zurückgeben!:

%Vor%     
Mitch Wheat 07.10.2008 14:57
quelle
2

Das ist eine schlechte Idee, weil ihre Verwendung Polymorphismus bricht. Der Typ der verwendeten Referenz sollte das Verhalten des Objekts NICHT verändern. Wenn Sie eine lose Kopplung sicherstellen möchten, müssen Sie die Klassen intern machen und eine DI-Technologie (wie Spring.Net) verwenden.

    
dpurrington 24.10.2008 17:57
quelle
2

Zweifellos gibt es bestimmte Vorteile, wenn es darum geht, die Benutzer Ihres Codes dazu zu zwingen, Ihre Objekte auf die Schnittstellentypen zu konvertieren, die sie verwenden sollen.

Aber im Großen und Ganzen ist die Programmierung einer Schnittstelle eine Methode oder ein Prozessproblem. Die Programmierung an einer Schnittstelle wird nicht nur dadurch erreicht, dass der Code für den Benutzer lästig wird.

    
yfeldblum 26.10.2008 14:18
quelle
1

Die Verwendung von Schnittstellen in dieser Methode führt an sich nicht zu entkoppeltem Code. Wenn das alles ist, was du tust, fügt es nur eine weitere Ebene der Verschleierung hinzu und macht es wahrscheinlich später verwirrender.

Wenn Sie jedoch Interface-basierte Programmierung mit Inversion von Control und Dependency Injection kombinieren, dann kommen Sie wirklich irgendwo hin. Sie können Mock Objects for Unit Testing auch mit dieser Art von Setup verwenden, wenn Sie Test Driven Development einsetzen.

Jedoch sind IOC, DI und TDD alle Hauptthemen an und für sich, und ganze Bücher wurden zu jedem dieser Themen geschrieben. Hoffentlich gibt Ihnen das einen Sprung von Dingen, die Sie erforschen können.

    
Nick 07.10.2008 14:57
quelle
1

Nun, es gibt einen organisatorischen Vorteil. Sie können ICuttingSurface, ICut und verwandte Funktionen in eine Assembly kapseln, die in sich abgeschlossen und einzeln testbar ist. Alle Implementierungen der ICut-Schnittstelle sind leicht sperrbar und können nur von der ICut-Schnittstelle und nicht von tatsächlichen Implementierungen abhängig gemacht werden, was zu einem modulareren und saubereren System führt.

Auch dies hilft, die Vererbung zu vereinfachen und gibt Ihnen mehr Flexibilität, um Polymorphismus zu verwenden.

    
Steve g 07.10.2008 14:54
quelle
1

Nur Anrufer, die einen expliziten Schnittstellentyp erwarten, dürfen sicherstellen, dass Methoden nur in dem Kontext sichtbar sind, in dem sie benötigt werden.

Betrachten Sie eine logische Entität in einem Spiel, und Sie entscheiden, dass anstelle einer Klasse, die für das Zeichnen / Markieren der Entitäten verantwortlich ist, die der Code für tick / draw in der Entität sein soll.

implementieren IDrawable.draw () und ITickable.tick () gewährleistet, dass eine Entity immer nur gezeichnet / angekreuzt werden kann, wenn das Spiel es erwartet. Sonst sind diese Methoden niemals sichtbar.

Geringerer Bonus: Wenn Sie mehrere Schnittstellen implementieren, können Sie mit expliziten Implementierungen Fälle umgehen, in denen zwei Schnittstellenmethoden kollidieren.

    
Krypes 24.10.2008 17:43
quelle
1

Ein weiteres mögliches Szenario für das explizite Implementieren einer Schnittstelle besteht im Umgang mit einer vorhandenen Klasse, die die Funktionalität bereits implementiert, aber einen anderen Methodennamen verwendet. Wenn Ihre Knife-Klasse beispielsweise bereits über eine Methode namens Slice verfügt, können Sie die Schnittstelle folgendermaßen implementieren:

%Vor%     
Michael Carman 12.06.2009 16:57
quelle
0

Wenn der Client-Code nichts anderes interessiert als die Tatsache, dass er das Objekt für Cut() sachen verwenden kann, verwenden Sie ICut .

    
skaffman 07.10.2008 14:54
quelle
0

Ja, aber nicht unbedingt aus den angegebenen Gründen.

Ein Beispiel:

In meinem aktuellen Projekt erstellen wir ein Tool zur Dateneingabe. Wir haben bestimmte Funktionen, die von allen (oder fast allen) Registerkarten verwendet werden, und wir codieren eine einzelne Seite (das Projekt ist webbasiert), die alle Dateneingabesteuerelemente enthält.

Auf dieser Seite befinden sich die Navigation und Schaltflächen für die Interaktion mit allen gängigen Aktionen.

Durch die Definition einer Schnittstelle (IDataEntry), die Methoden für jede der Funktionen implementiert und diese Schnittstelle für jede der Steuerelemente implementiert, können die aspx-Seiten öffentliche Methoden für die Benutzersteuerelemente auslösen, die die eigentliche Dateneingabe durchführen / p>

Indem Sie eine Reihe von Interaktionsmethoden definieren (wie zum Beispiel Ihre 'cut'-Methode), können Sie mit einem Interface ein Objekt (sei es ein Business-Objekt, ein Web-Control oder was Sie haben) aufnehmen und damit arbeiten in einer definierten Weise.

Für Ihr Beispiel können Sie ein ICut-Objekt, sei es ein Messer, eine Säge, eine Lötlampe oder ein Monofilament-Draht, schneiden.

Zu Testzwecken denke ich, Schnittstellen sind auch gut. Wenn Sie Tests basierend auf der erwarteten Funktionalität der Schnittstelle definieren, können Sie Objekte wie beschrieben definieren und testen. Dies ist ein Test auf sehr hohem Niveau, aber es stellt immer noch Funktionalität sicher. JEDOCH sollte dies nicht die Einheitsprüfung der einzelnen Objektmethoden ersetzen ... es ist nicht gut zu wissen, dass 'obj.Cut' zu einem Schnitt geführt hat, wenn es dazu geführt hat, dass das falsche Teil abgeschnitten wurde oder an der falschen Stelle.

    
Jeff 07.10.2008 14:57
quelle

Tags und Links