Posizionamento accettabile della radice di composizione mediante contenitori di dipendenza di input (DI) e inversione di controllo (IoC)

8

Ho letto in diverse fonti, tra cui il blog di Ploeh di Mark Seemann su come l'appropriato il posizionamento della root di composizione di un contenitore IoC è il più vicino possibile al punto di ingresso di un'applicazione.

Nel mondo .NET, queste applicazioni sembrano essere comunemente pensate come progetti Web, progetti WPF, applicazioni console, cose con un'interfaccia utente tipica (leggi: non progetti di libreria).

È davvero contrario a questo consiglio saggio di posizionare la radice di composizione nel punto di ingresso di un progetto di libreria, quando rappresenta il punto di ingresso logico di un gruppo di progetti di libreria e il client di un gruppo di progetto come questo è il lavoro di qualcun altro, il cui autore non può o non vuole aggiungere la radice di composizione al proprio progetto (un progetto di interfaccia utente o ancora un altro progetto di libreria, anche)?

Ho familiarità con Ninject come un'implementazione del contenitore IoC, ma immagino che molti altri lavorino allo stesso modo in quanto possono cercare un modulo contenente tutte le configurazioni di rilegatura necessarie. Ciò significa che potrei inserire un modulo di binding nel proprio progetto di libreria per compilare l'output del progetto della mia libreria principale e, se il cliente volesse modificare la configurazione (uno scenario improbabile nel mio caso), potrebbe rilasciare una dll di sostituzione per sostituire il libreria con il modulo di binding.

Questo sembra evitare che i client più comuni abbiano a che fare con l'integrazione delle dipendenze e le radici di composizione, e farebbero l'API più pulita per il gruppo di progetto della biblioteca.

Tuttavia questo sembra volare di fronte alla saggezza convenzionale sulla questione. E 'solo che la maggior parte dei consigli là fuori fa presupporre che lo sviluppatore abbia un certo coordinamento con lo sviluppo dei progetti UI, piuttosto che il mio caso, nel quale sto solo sviluppando librerie che altri possano usare?

    
posta Jeff 10.04.2013 - 05:59
fonte

4 risposte

2

L'approccio del modulo vincolante è la soluzione migliore. Se è improbabile che il client cambi la configurazione, l'uso di DI è discutibile, per la tua libreria in particolare.

Se desideri creare una libreria per il rilascio al pubblico, probabilmente non vuoi che i clienti affrontino la complessità o la rigidità del particolare sistema DI che preferisci al momento. Le librerie sono le migliori quando sono componenti di livello inferiore che possono essere utilizzate senza un sacco di dipendenze o una formazione approfondita. Qualsiasi sistema DI selezionato cambierà nel tempo e potrebbe diventare incompatibile con le applicazioni client.

    
risposta data 29.04.2014 - 18:11
fonte
2

Si suppone che una libreria sia una scatola nera con un'API specifica per dominio pulita. Non c'è alcun problema con l'utilizzo di qualsiasi strumento o pattern di cui hai bisogno all'interno di una libreria, incluso DI, a condizione che non perda al client e lo vincoli in qualche modo.

Se è necessario fornire estensibilità o modifiche alla configurazione della libreria, è comunque possibile eseguirlo senza condividere una singola radice di composizione tra la libreria e il client.

Se puoi giustificare la tua libreria a seconda di un'altra libreria di terze parti solo per implementare DI nella tua libreria, è un problema diverso, ma tieni presente che lo stesso pattern DI può essere implementato senza alcuna dipendenza.

    
risposta data 12.09.2014 - 12:27
fonte
-1

Se stai sviluppando librerie (non applicazioni) da utilizzare per altri, allora dovresti comunque implementare l'integrazione delle dipendenze. Per me il termine "Iniezione di dipendenza" è solo un insieme di pratiche che portano a una migliore separazione delle preoccupazioni e un accoppiamento lento. Questo è ciò che rende la tua biblioteca ben strutturata e facilmente testabile (il più delle volte).

Per quanto riguarda il contenitore IoC, non vedo alcun danno nell'avere un contenitore IoC nel progetto della libreria. Da qualche parte avrai una radice di composizione (un punto di ingresso) nella tua biblioteca, quindi per me ha perfettamente senso collegare le dipendenze nella radice della composizione. Come lo fai dipende interamente da te.

Ad esempio, ho recentemente utilizzato una libreria per l'acquisizione di firme e una libreria per la scansione di codici a barre. Entrambi erano semplici librerie di interoperabilità (wrapper COM). Ogni libreria mi ha richiesto di inizializzarla prima di poter fare qualsiasi cosa. Ad esempio:

var isReady = _signatureCapture.Initialise()
if (isReady)
{
   // Do stuff
}

La libreria di scansione dei codici a barre era molto simile:

_scanner.Initialise();
_scanner.OnScan += OnScanHandler;

Ho usato entrambe le librerie e non ho idea se usano o meno il contenitore IoC. Tuttavia, so che i punti di ingresso nella libreria sono nei metodi Initialise . Suppongo che tutte le dipendenze siano cablate nel metodo Initialise , che funge da radice di composizione.

Se sei preoccupato di affidarti a un contenitore IoC di terze parti, allora puoi implementare la tua implementazione molto più semplice. Gli sviluppatori spesso si preoccupano che la biblioteca diventi obsoleta o sostituita da qualcosa di meglio, ma in realtà non ho ancora visto un progetto in cui il team ha deciso di sostituire un contenitore IoC per l'altro.

    
risposta data 29.04.2014 - 19:01
fonte
-2

La bellezza delle librerie esterne è che dovrebbero fare sempre ciò che dicono di fare, esponendo un'interfaccia semplice e diretta. Quanto sia complesso, in realtà, è farlo, non dovrebbe essere il business dello sviluppatore che lo implementa. Se DI in effetti rende il lavoro dello sviluppatore dell'API meno complesso, allora ha senso al 100% usarlo, a condizione che venga utilizzato correttamente e che il suo modulo sia dichiarato al punto di ingresso dell'API. Di recente, durante lo sviluppo di un'app MVC, ho astratto il livello dati utilizzando un modello di repository e ulteriormente astruso posizionando un livello di servizio tra l'app MVC e il livello del repository, entrambi sono stati progetti di Class Library. Ho avuto un'interfaccia ICache mappata su una classe cache per il mio contesto di servizio. Inizialmente l'ho implementato usando MVC.Web.Cache, ma in una successiva Iteration l'ho sostituito per System.runtime.cache e puoi solo immaginare quanto grande fosse la scala di quel Refactor senza il mio DI. Quindi il mio consiglio; "Vai per questo".

    
risposta data 02.09.2014 - 04:51
fonte