Come utilizzare Iniezione delle dipendenze in combinazione con il modello di fabbrica

11

Considera un modulo responsabile dell'analisi dei file di un determinato tipo. Sto pensando di utilizzare il modello di strategia per affrontare questo problema, come ho già spiegato su qui . Si prega di fare riferimento al post collegato prima di procedere con questa domanda.

Considera la classe B che richiede il contenuto del file product.xml. Questa classe dovrà istanziare l'appropriato implementatore concreto dell'interfaccia di Parser per analizzare il file XML. Posso delegare l'istanziazione di un appaltatore concreto appropriato a una fabbrica in modo tale che la classe B "abbia una fabbrica". Tuttavia, la classe B "dipenderà" da una fabbrica per l'istanziazione dell'operatore di calcestruzzo. Ciò significa che il costruttore o un metodo setter nella classe B dovranno essere passati alla fabbrica.

Pertanto, Factory e la classe B che deve analizzare un file saranno strettamente accoppiate tra loro. Capisco che potrei avere completamente torto su tutto ciò che ho spiegato finora. Vorrei sapere se posso usare l'iniezione di dipendenza in uno scenario in cui la dipendenza da iniettare è una Fabbrica e quale sarebbe il modo giusto di implementarla, così posso approfittare di aree come la simulazione della Fabbrica nei miei test di unità.

    
posta CKing 22.02.2013 - 12:09
fonte

4 risposte

8

Il modo giusto per fare ciò è dipendere da un'interfaccia e quindi iniettare un'implementazione di tale interfaccia in Classe B.

Un'interfaccia è solo la cosa più sottile da cui si possa dipendere: la paragono al tentativo di afferrare un filo di fumo. Il codice deve accoppiarsi con qualcosa altrimenti non farà nulla, ma l'accoppiamento ad un'interfaccia è approssimativamente disaccoppiato come si può ottenere, tuttavia le interfacce possono fornire tutte le funzionalità che si possono desiderare.

Quindi, il costruttore della classe B ha un'interfaccia per la classe di cui ha bisogno e ha la fabbrica che produce quella classe come implementatore dell'interfaccia. Non fare affidamento sulla fabbrica, dipendere dall'interfaccia e fare in modo che la fabbrica fornisca un'implementazione di quella fabbrica.

Quindi sì, userete l'iniezione di dipendenza, ma non c'è niente di sbagliato in questo. L'iniezione di dipendenza, in particolare l'iniezione di un costruttore, dovrebbe essere il modo "normale" di fare le cose. Semplicemente rimandare cose nuove alla tua app (e quanto più vicino alla prima riga di main ) possibile, e nascondere la nuova chiamata in una classe progettata specificamente per creare cose.

In conclusione: non esitare a iniettare dipendenze. Questo dovrebbe essere il modo normale di fare le cose.

    
risposta data 22.02.2013 - 16:15
fonte
9

Penso che la tua premessa sia un po 'confusa qui, parli di iniezione di una fabbrica, ma il pattern factory è un modello creativo il cui scopo era quello di fare un sottoinsieme di ciò che fa un framework di injection dependance, quando i framework DI non erano prevalenti questo modello è stato utile per questo motivo. Tuttavia, se si dispone di un framework DI, non è più necessaria una factory in quanto il framework DI può soddisfare lo scopo che la fabbrica avrebbe soddisfatto.

Detto questo, lascia che ti spieghi un po 'di iniezione di dipendenza e in che modo lo useresti generalmente.

Esiste una varietà di modi per fare l'iniezione di dipendenza, ma i più comuni sono l'iniezione del costruttore, l'iniezione di proprietà e il DIContainer diretto. Parlerò dell'iniezione del costruttore poiché l'iniezione di proprietà è l'approccio sbagliato per la maggior parte del tempo (l'approccio giusto alcune volte) e l'accesso a DIContainer non è preferibile tranne quando non si può assolutamente fare nessuno degli altri approcci.

L'iniezione del costruttore è dove hai l'interfaccia per una dipendenza e un DIContainer (o fabbrica) che conosce l'implementazione concreta per quella dipendenza, e dovunque hai bisogno di un oggetto che dipende da quell'interfaccia, al momento della costruzione passi l'implementazione da la fabbrica ad esso.

cioè.

IDbConnectionProvider connProvider = DIContainer.Get<IDbConnectionProvider>();
IUserRepository userRepo = new UserRepository(connProvider);
User currentUser = userRepo.GetCurrentUser();

Molti framework DI possono semplificare in modo significativo il punto in cui il tuo DIContainer ispezionerà il costruttore di UserRepository per le interfacce per cui conosce le implementazioni concrete e lo consegnerà automaticamente a te per te; questa tecnica viene spesso chiamata Inversion of Control, sebbene DI e IoC siano entrambi termini che vengono scambiati molto e presentano differenze vaghe (se presenti).

Ora, se ti stai chiedendo come il codice sovrastante acceda al DIContainer, beh, puoi avere una classe statica per accedervi, o ciò che è più appropriato è che la maggior parte dei framework DI ti consente di creare un nuovo DIContainer, in cui sarà effettivamente comportati come un wrapper per un dizionario Singleton interno per i tipi che sa essere concreti per determinate interfacce.

Ciò significa che puoi rinnovare il DIContainer ovunque nel codice e ottenere effettivamente lo stesso DIContainer che avevi già configurato per conoscere le tue relazioni da interfaccia a concrete. I soliti mezzi per nascondere il DIContainer da parti del codice che non dovrebbero interagire direttamente con esso è semplicemente assicurare che solo i progetti necessari abbiano un riferimento al framework DI.

    
risposta data 22.02.2013 - 18:03
fonte
5

Puoi passare una fabbrica tramite l'iniezione delle dipendenze proprio come fai per passare qualcos'altro, non lasciare che la ricorsività della situazione ti confonda. Non so cos'altro dire sull'implementazione - sai già come fare l'iniezione di dipendenza.

Uso DI per iniettare le fabbriche abbastanza regolarmente.

    
risposta data 22.02.2013 - 20:48
fonte
4

Non c'è niente di sbagliato nell'iniettare le fabbriche. È un modo standard se non puoi decidere durante la compilazione dell'oggetto "genitore" di quale tipo di dipendenza ti servirà. Penso che l'esempio spiegherà meglio. Userò c # perché non conosco java.


class Parent
{
    private IParserFactory parserFactory;
    public Parent(IParserFactory factory)
    {
        parserFactory = factory
    }

    public ParsedObject ParseFrom(string filename, FileType fileType)
    {
        var parser = parserFactory.CreateFor(fileType);
        return parser.Parse(filename);
    }
}
    
risposta data 22.02.2013 - 21:24
fonte

Leggi altre domande sui tag