Come evitare di utilizzare il percorso del servizio quando si utilizza l'iniezione delle dipendenze? [chiuso]

0

Sto tentando di utilizzare l'integrazione delle dipendenze in un'applicazione WPF e non riesco davvero a capire come evitare l'uso del servizio, che è considerato un anti-pattern in molti articoli. Sto usando il framework MVVM Light.

Interface I
  Property N As Integer
End Interface
Class A
  Private _i As I
  Sub New(i As I)
    _i = i
  End Sub
  Sub DoWork()
    _i.N = 1
  End Sub
End Class
Class B
  Implements I
  Property N As Integer Implements I.N
End Class
Class C
  Sub DoSomething()
    REM IS THIS ANTI-PATTERN???
    Dim instanceA = SimpleIoc.Default.GetInstance(Of A)()
    instanceA.DoWork()
  End Sub
End Class
Module M
  Sub Main()
    SimpleIoc.Default.Register(Of A)()
    SimpleIoc.Default.Register(Of I, B)()
    Dim c As New C
    c.DoSomething()
  End Sub
End Module

Quando ho bisogno di usare un'istanza di A nella classe C , è un anti-pattern per usare il contenitore IoC come localizzatore di servizi? C'è un altro modo per autocostruire un'istanza di A con le dipendenze richieste?

    
posta Ondřej 12.08.2015 - 10:57
fonte

2 risposte

2

Il problema è che stai usando "Dim c As New C", invece di registrare C nel contenitore IoC e richiederlo da lì. Le richieste di dipendenza C in DoSomething devono essere passate nel costruttore, quali cavi IoC per te. Ciò che rende un po 'difficile è il fatto che il tuo contenitore IoC sembra essere un Singleton ed è quindi accessibile da qualsiasi luogo. Dovresti provare ad evitarlo.

La posizione del servizio è in effetti un antipattern, ma è necessario utilizzare la posizione del servizio almeno ONCE affinché la tua applicazione funzioni, come hai giustamente fatto nella tua domanda. Questo viene fatto creando una classe di applicazione principale che viene recuperata manualmente dal contenitore IoC. Il resto della tua applicazione va da lì. Se fai le cose bene, ottieni una singola classe principale dal contenitore IoC e il resto è collegato dal contenitore stesso. Si trasforma in antipattern solo quando inizi a intersecare questo codice IoC in un altro codice di applicazione.

Pensare alle dipendenze aiuta effettivamente il tuo codice. È molto più facile vedere dove stai andando male con il design di una classe se stai aggiungendo la settima dipendenza al costruttore, invece di New'ing fino alla settima classe in un metodo. Una volta che hai preso la testa per pensare in termini di IoC, inizi a scrivere classi piccole, focalizzate e ben testabili, ma devi affondare i denti per un po 'fino a quando non inizierai davvero a vedere i vantaggi.

    
risposta data 12.08.2015 - 12:00
fonte
0

Prima di tutto, sì. Usare un IoC in questo modo è un anti-modello. Hai una variabile globale sotto mentite spoglie.

È naturale che le dipendenze "esplodano" verso il punto di ingresso del programma e che i costruttori crescano di dimensioni. Questa è solo la natura della bestia. Tuttavia, facciamo un passo indietro e poniamoci una domanda.

Why do we want DI to begin with?

Vogliamo DI in modo che possiamo facilmente falsificare le dipendenze per test più facili. Sono testati. Questi enormi costruttori non devono mai essere chiamati nel codice di produzione.

Puoi usare un IoC per questo, ma non devi. Abbandona se vuoi.

Potrei ottenere una crema per questo, ma qui non va niente ...

Ho scelto questo trucco da Lavorare efficacemente con il codice legacy di Michael Feathers , ma vorrei essere chiaro che Sto abusando della tecnica per ridurre le dimensioni dei costruttori che vengono effettivamente chiamati nel codice di produzione.

Molto spesso, le dipendenze lungo la catena non cambiano in fase di esecuzione. Sono effettivamente costanti, ma vogliamo ancora la capacità di fingere quelle dipendenze. Considera il seguente esempio. (Scusa il mio C # per favore)

public class Class1
{
    public Class1(Foo foo, Bar bar, Qux qux)
    {
        //...
    }
 }

In realtà, il nostro codice di produzione utilizza sempre gli stessi valori per tutti i nostri parametri. Va bene. Sovraccaricare il ctor e creare le nuove istanze al suo interno. (È una bestemmia, lo so. Non importa, funziona.)

public class Class1
{
    public Class1(Foo foo, Bar bar, Qux qux)
    {
        //....
    }

    public Class1()
        :this(new Foo(), new Bar(), new Qux())
    {
        //...
    }
 }

Ora il tuo codice di produzione chiama il costruttore senza parametri ei tuoi test chiamano il costruttore real . Problema risolto. Non è necessario alcun quadro di fantasia. Certo, dovrebbe essere un modo per realizzare la stessa cosa con il tuo framework IoC, ma senza conoscere i dettagli di quello che stai usando, non posso dire come. Sfortunatamente, VB.Net non ha lo stesso amore quando si tratta di framework come C #. Indipendentemente da ciò, ho pensato che dovresti vedere il modo "veloce e sporco" per farlo. È sempre possibile passare a un contenitore IoC in un secondo momento, quando i progetti sono sufficientemente complessi da giustificarlo.

    
risposta data 13.08.2015 - 02:13
fonte