2015-07-28 19 views
9

Gibt es einen Vorteil, Schnittstellen explizit in Bezug auf Dependency Injection zu implementieren?Abhängigkeitsinjektion und explizite Schnittstellenimplementierung

Soweit ich verstehe, kann Schnittstellen entweder explizit oder implizit implementiert werden:

interface IFoo 
{ 
    void Bar(); 
} 

//implicit implementation 
class Foo1 : IFoo 
{ 
    public void Bar(){} 
} 

//explicit implementation 
class Foo2 : IFoo 
{ 
    void IFoo.Bar(){} 
} 

Nun ist die explizite Implementierung nur durch den Aufruf der Interface-Methode, während die implizite Umsetzung direkt aufgerufen werden kann auf ein aufgerufen werden kann Instanz der Klasse:

class Baz 
{ 
    void Ba() 
    { 
     Foo1 foo1 = new Foo1(); 
     foo1.Bar(); 

     Foo2 foo2 = new Foo2(); 
     foo2.Bar(); //syntax error 

     IFoo foo2_explicit = new Foo2(); 
     foo2_explicit.Bar(); 
    } 
} 

So expliziten Schnittstellenimplementierungen unter Verwendung einer eine Methode für eine konkrete Klasse nicht zufällig nennen kann, aber man muss das Interface-Methode aufzurufen. Verhindert dies einen eng gekoppelten Code, wie es ein Zweck von DI ist, oder banne ich hier den falschen Baum? Immerhin kann man nicht aus Versehen einen Konstruktor oder eine Methode schreiben, die eine konkrete Klasse statt einer Schnittstelle injiziert wird:

class Baz 
{ 
    void Ba(Foo2 foo) 
    { 
     foo.Bar(); //syntax error 
    } 

    void Bb(IFoo foo) 
    { 
     foo.Bar(); 
    } 
} 
+2

Können Sie Ihren Code aktualisieren, um IFoo anstelle von Foo zu verwenden?Es ist verwirrend meiner Meinung nach ... –

+0

Geschehen - sorry, in der Regel respektiere ich Code Konventionen ... – Thaoden

Antwort

8

Normalerweise ist der Zweck der Dependency Injection ist Entkopplung, die Sie durch Injizieren der Abstraktion in seine Client erreichen:

public class Baz 
{ 
    private readonly IFoo foo; 

    public Baz(IFoo foo) 
    { 
     this.foo = foo; 
    } 

    // Members using this.foo go here... 
} 

Dies stellt sicher, dass Baz auf IFoo abhängt und von jedem konkreten entkoppelt Implementierung.

Ob eine Betonklasse IFoo implizit oder explizit implementiert, spielt keine Rolle.

Hin und wieder kann eine Klasse eine Concrete Dependency haben, aber das ist nicht besonders normal; und wenn es passiert, ist die konkrete Abhängigkeit Beton, so oft wird überhaupt keine Schnittstelle implementieren. Explizite oder implizite Schnittstellenimplementierung ist in solchen Fällen irrelevant.

+0

Das ist, was ich versuche, zu erhalten. Wenn man aus einem obskuren Grund nicht aufpasst und einen Konstruktor schreibt, der eine konkrete Klasse erwartet: 'public Baz (Foo1 foo) ', verbietet die Verwendung von expliziten Interface-Implementierungen jegliche Aufrufe an die Methoden des Objekts. Der Versuch, eine konkrete Implementierung an die Schnittstelle zu werfen, würde einige Alarmglocken läuten, oder? – Thaoden

+0

Wenn Sie ** versehentlich ** einen Konstruktor hinzufügen, der die konkrete Klasse erwartet, dann haben Sie gerade die Entkopplung verloren, die der Zweck der Dependency-Injektion ist. Das ist ein viel größeres Problem mit dem Dienst und sollte an der Wurzel des Problems gelöst werden, anstatt von irgendeinem beliebigen Client gepatcht zu werden. –

1

Wenn Ihre Klasse in Behälter ist, dann verwenden Sie Schnittstelle. Also, es gibt keine Vorteile.

Aber, wenn Sie Ihre Klasse direkt verwenden (in Tests zum Beispiel), müssen Sie umwandeln, um auf die Methode zuzugreifen, und es ist nicht bequem.

Insgesamt: 0 Vorteile, wenn Sie Klasse in Container und schlecht für Tests verwenden.

0

Meiner Meinung nach sollte man immer einen Verweis auf ein Objekt behalten, dessen Typ "gerade genug" ist. Betrachten Sie das folgende Beispiel:

public interface IDo 
{ 
    void Do(); 
} 

public interface IWatch 
{ 
    void Watch(); 
} 

public class Foo : IDo, IWatch 
{ 
    public void Dummy() { } 

    public void Watch() { } 

    public void Do() { } 
} 

und dann:

//I only want to use Do() 
IDo aFoo = new Foo(); 

//I only want to use Watch() 
IWatch bFoo = new Foo(); 

//I want to use stuff from Foo and optionally stuff from IDo or IWatch 
Foo cFoo = new Foo(); 

Wenn es um die Verwendung von Dependency Injection Container wie MEF oder Unity sollten Sie eine Schnittstelle verwenden, um ein Objekt in den Container zu exportieren und importieren Sie es mit der gleiche Schnittstellentyp.

Nach diesen Mustern sehe ich keinen wirklichen Vorteil bei der Verwendung expliziter Schnittstellenimplementierungen. (Es erschwert auch die Suche nach Implementierungsmethoden in den Standard-Visual Studio-Kombinationsfeldern über Ihrem Texteditor.)

Verwandte Themen