2015-07-28 11 views
9

Esiste un beneficio che implementa le interfacce in modo esplicito rispetto all'iniezione delle dipendenze?Implementazione delle dipendenze e implementazione di un'interfaccia esplicita

Per quanto ho capito, le interfacce possono essere implementate in modo esplicito o implicito:

interface IFoo 
{ 
    void Bar(); 
} 

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

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

Ora l'implementazione esplicita può essere chiamato solo chiamando il metodo di interfaccia, mentre l'attuazione implicita può essere chiamato direttamente su un istanza della classe:

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(); 
    } 
} 

Così, usando le implementazioni di interfacce esplicite, non si può accidentalmente chiamare un metodo su una classe concreta, ma si deve chiamare il metodo di interfaccia. Questo impedisce il codice strettamente accoppiato come è uno scopo di DI o sto abbaiando l'albero sbagliato qui? Dopo tutto, non si può accidentalmente scrivere un costruttore o un metodo che ottiene una classe concreta iniettato al posto di un'interfaccia:

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

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

Potresti aggiornare il tuo codice per utilizzare IFoo invece di Foo?A mio avviso è confuso ... –

+0

Fatto - scusate, di solito rispetto le convenzioni del codice ... – Thaoden

risposta

8

Normalmente, allo scopo di iniezione di dipendenza è disaccoppiamento, che a raggiungere iniettando l'astrazione nel suo client:

public class Baz 
{ 
    private readonly IFoo foo; 

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

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

Questo assicura che Baz dipende IFoo, ed è disaccoppiati da qualsiasi cemento implementazione.

Se una classe concreta implementa o meno IFoo in modo implicito o esplicito non fa alcuna differenza.

Una volta ogni tanto, una classe può avere un Concrete Dependency, ma questo non è particolarmente normale; e quando accade, la dipendenza concreta è calcestruzzo, così spesso non implementerà affatto un'interfaccia. L'implementazione esplicita o implicita dell'interfaccia è irrilevante in questi casi.

+0

Questo è quello che stavo cercando di ottenere. Se per qualche oscuro motivo non si prestava attenzione e si scriveva un costruttore che si aspettava una classe concreta: 'public Baz (Foo1 foo)', l'uso di implementazioni esplicite dell'interfaccia vietava qualsiasi chiamata ai metodi dell'oggetto. Cercando di gettare una implementazione concreta alla sua interfaccia suonerebbe qualche campanello d'allarme, allora, no? – Thaoden

+0

Se ** per caso ** aggiungi un costruttore che si aspetta la classe concreta, hai appena perso il disaccoppiamento che è lo scopo di Dipendenza dell'iniezione. Questo è un problema molto più grande con il servizio, e dovrebbe essere risolto alla radice del problema, invece di essere corretto da qualche client arbitrario. –

1

Se la classe è in un contenitore, quindi si utilizza l'interfaccia. Quindi, non ci sono benefici.

Tuttavia, se si utilizza direttamente la classe (nei test ad esempio) è necessario eseguire il cast per accedere al metodo e non è conveniente.

Totale: 0 vantaggi quando si utilizza la classe nel contenitore e non valida per i test.

0

A mio parere, in generale si dovrebbe sempre mantenere un riferimento a un oggetto il cui tipo è "appena sufficiente" da utilizzare. Si consideri il seguente esempio:

public interface IDo 
{ 
    void Do(); 
} 

public interface IWatch 
{ 
    void Watch(); 
} 

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

    public void Watch() { } 

    public void Do() { } 
} 

e poi:

//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(); 

Quando si tratta di utilizzare contenitori iniezione di dipendenza come MEF o Unity si dovrebbe usare un'interfaccia per esportare un oggetto nel contenitore e importarlo con lo stesso tipo di interfaccia.

Seguendo questi schemi, non vedo davvero alcun vantaggio nell'utilizzo di implementazioni esplicite dell'interfaccia. (Rende anche più difficile localizzare i metodi di implementazione nelle combobox standard di Visual Studio sopra l'editor di testo)

Problemi correlati