Iniezione delle dipendenze e facilità d'uso

2

Sto scrivendo una pratica libreria (la chiameremo Thinger) che si spegne e recupera un documento XML, fa una query X-Path su di esso e fa qualcosa di utile con il risultato di ciò. (Quello che sto facendo è troppo noioso per infastidire tutti, questo è solo un esempio semplificato.)

Poiché sono un programmatore saggio e pigro, sto facendo uso di due componenti di terze parti, uno per il recupero di documenti XML remoti (che chiameremo Fetcher) e uno per l'esecuzione di query X-Path (lo faremo chiamalo Querier).

La mia libreria fornisce una classe Thinger, in cui è necessario iniettare un Fetcher e un interrogante. Potrei farlo tramite setter o un costruttore.

Ma poi penso alle persone povere che usano la mia biblioteca, che ora devono pensare a iniettare le mie dipendenze quando tutto ciò che vogliono veramente è chiamare qualcosa come

new Fetcher()->fetch(someurl);

Finora, ho scritto una fabbrica statica che istanzia un nuovo Thinger, Fetcher e Querier, li assembla come appropriato e restituisce il Thinger.

Questo mi ha lasciato leggermente impuro.

Sicuramente c'è un modo migliore?

Modifica

La maggior parte dei framework ecc probabilmente si aggirerebbe usando un Dependency Injection Container o qualcosa di simile, ma dal momento che sto scrivendo una libreria di terze parti abbastanza piccola che sembra un cattivo approccio.

    
posta Jez 10.05.2013 - 18:12
fonte

3 risposte

7

Poiché Dependency Inversion sembra diventare sempre più popolare, vorrei fare un doppio approccio.

  1. Progetta i componenti da utilizzare con un contenitore di iniezione delle dipendenze, se possibile per l'uso con un contenitore arbitrario in modo da non vincolare gli utenti nella loro scelta.
  2. Come opzione di convenienza, fornisci anche un factory (-method) per creare un Thinger con Fetcher e Querier predefiniti.
risposta data 10.05.2013 - 18:43
fonte
4

Che cosa c'è di sbagliato nel fornire una bella implementazione predefinita pulita per lo scenario comune, consentendo al contempo una versione iniettata per le persone che desiderano tale flessibilità?

Finché l'implementazione predefinita non impone vincoli di annullamento sull'utilizzo (come l'eliminazione manuale di Fetcher e Querier ) o l'implementazione predefinita è comune solo per la minoranza, ciò sembra perfettamente soddisfacente.

    
risposta data 10.05.2013 - 18:43
fonte
1

Utilizzare un'inversione del contenitore di controllo. In .NET questo include Castle Windsor o NInject

Puoi semplicemente specificare quali componenti hai bisogno nel costruttore e puoi ottenere un oggetto come questo

IThinger thinger = container.Resolve<IThinger>();
thinger.DoTheStuff();

Il codice sopra non interessa quale implementazione di IKing hai, quale dipendenza deve essere iniettata, ecc.

Non ha bisogno di molte impostazioni o configurazioni complicate. Normalmente, devi scrivere solo un metodo o un file in cui registrare tutti i tuoi servizi (come Thinger, Fetcher) e inizializzare il contenitore con quella registrazione

    
risposta data 10.05.2013 - 18:19
fonte