Come utilizzare correttamente i contenitori di iniezione di dipendenza quando nascondono le dipendenze dalle classi esterne?

2

Da Zend Docs c'è questo esempio di come usare Zend\Di , che è un contenitore per le dipendenze di Zend Framework:

// inside a bootstrap somewhere
$di = new Zend\Di\Di();

// inside each controller
$movieLister = $di->get('MyMovieApp\MovieLister');

Le indicazioni su come ottenere $di nel controller non sono fornite nei documenti e lasciate all'implementazione del lettore. Questo potrebbe essere, ad esempio, iniettare $di nel controller (nasconde dipendenze), o avere $di essere globale per l'ambito dell'applicazione (uso di globali) o creare $di all'interno del controller come variabile locale (sembra meno problematico ma nasconde le dipendenze). Il risultato finale è .. $di è all'interno del controller e ready & disponibile per l'uso.

Nell'esempio, l'uso di DiC nasconde la dipendenza del controllore su MovieLister . Non sai che il controllore usa MovieLister osservando la firma della classe, i metodi setter o qualsiasi parametro a livello di classe.

Perché è giusto "nascondere le dipendenze" dalle classi che chiamano il controller?

DiC sembra essere uno schema di progettazione accettabile da utilizzare in questi giorni. Qual è l'uso corretto? Perché non usarlo al di fuori di un Controller, ad esempio in un ControllerFactory o altrove? Si può evitare il nascondimento delle dipendenze con l'uso di DiC?

    
posta Dennis 17.07.2017 - 17:11
fonte

2 risposte

3

Non so come funzioni Zend, ma indipendentemente dal framework, nascondere le dipendenze blocca il codice nel contenitore DI, offuscare il codice, rende il design opaco e orientato alla magia. In generale, rende il nostro progetto più difficile da capire.

Costruttori e setter parametrizzati rendono il nostro codice meno orientato alla magia e meno incline a Poltergeist . Alcuni contenitori ci permettono di eliminare queste meraviglie dal codice, ma perché dovremmo? 1

Per quanto riguarda ServiceLocator come alternativa

For RAD, when Controllers ask for a lot of dependencies, when business logic is complex enough, instead of cluttering Controller constructor methods with 5+ dependencies, it is at times more convenient to pass the Service Locator / container as the dependency to the Controller and let code inside the Controller invoke various many objects via SL/DiC facilities.

Non sono d'accordo per i seguenti motivi:

  1. ServiceLocator nasconde ancora le dipendenze e non semplifica il test. Al contrario.

  2. Se i controller hanno così tante dipendenze, non hanno troppe responsabilità pure? ServiceLocator è quindi in grado di nascondere la mia debolezza progettuale o semplicemente di contribuire a loro?

  3. it is at times more convenient to pass the Service Locator/container as the dependency .

    Dove è finita la presunta astrazione?

  4. let code inside the Controller invoke various many objects via SL/DiC facilities .

    Dove è andato IoC?

Che cosa fa il contenitore per noi? Se usiamo il contenitore qua e là, dov'è la consistenza?

In Java, Spring fa la stessa magia, ma non mi impedisce di implementare costruttori e setter e di imporre il framework per usarli tutti. Il mio ragionamento è che più mi cado nelle strutture di primavera più mi blocco i miei sviluppi per il quadro. In definitiva, non sono un ingegnere senior di primavera.

Riassumendo, non nascondere le tue dipendenze. Rendili ovvi e ovvii saranno i tuoi disegni e non chiuderti a uno strumento specifico.

1: Questo è il dolce che dovremmo evitare. Genera un debito tecnico "personale" che alla fine ritorna contro di te.

    
risposta data 17.07.2017 - 23:46
fonte
0

Non usarli

... senza restrizioni. Ma usali quando il loro uso è ristretto a uno specifico ruolo ben mantenuto, in quanto ciò facilita la manutenzione del software ed evita il nascondimento delle dipendenze.

In primo luogo, alcuni sfondi.

Nel contesto dell'architettura di Zend Framework 2+, l'iniezione di qualsiasi DiC in un controller significa utilizzare quel DiC come localizzatore di servizi. (In Zend Framework, l'implementazione concreta di Service Locator si chiama ServiceManager ).

Per l'uso puro di DiC come DiC esiste un modello Register Resolve Release (RRR), che crea il controller per te e lo popola con dipendenze. Di norma, non si inserisce DiC nel controller, anche se lo si potrebbe fare, quindi si mischiano i modelli DiC e Service Locator.

Questo link è utile per fornire maggiori dettagli sulle differenze: link

Consigli della community

Inoltre, ci sono stati alcuni consigli su evitare l'uso di DiC , perché del più lento PHP Reflection API e vari problemi di manutenzione lungo la strada. DiC semplifica l'utilizzo di dipendenze complesse con conseguente creazione di grafici di dipendenza complessi che vengono creati automaticamente senza il cablaggio esplicito del codice manuale. Ciò rende difficile eseguirne il debug quando le cose vanno male. Se si aggiungono nuove dipendenze nel tempo, il ricablaggio automatico viene eseguito automaticamente senza scrivere codice di cablaggio esplicito. Ciò rende potenzialmente più difficile tenere traccia delle dipendenze manualmente quando qualcosa va storto. Si consiglia quindi di utilizzare il modello di localizzazione del servizio in quanto limita il valore di fabbrica a Di, offrendo un controllo più esplicito di Di tramite la configurazione esplicita.

Per RAD, quando i Controllori richiedono molte dipendenze, quando la logica aziendale è abbastanza complessa, invece di ingombrare i metodi del costruttore di Controller con più di 5 dipendenze, è a volte più conveniente passare il Service Locator / container come dipendenza a il Controller e il codice all'interno del Controller invocano vari oggetti tramite le strutture SL / DiC.

Per i non-RAD, suddividi i tuoi controller in punti in cui non hanno molte dipendenze.

Inoltre:

"Besides ZF2 controllers, I recommend not to inject ZendDiCompiler directly anywhere. If you need a service in one of your classes, just ask for it in the constructor"

From: dependency-injection-container-vs-service-locator

Tuttavia, non consiglio di iniettare DiC nei controller. Leggi qui sotto perché.

Utilizzo dell'indicatore di servizio

Non utilizzare Service Locator senza restrizioni. È stato ritirato in Zend per buoni motivi .

Utilizza la versione limitata di Service Locator come ad esempio come viene utilizzato in Zend Framework versione 3. È limitato a essere un Localizzatore di servizio con configurazione hardcoded basato su factory implementato tramite ServiceManager class. Collega il routing ai controllori tramite l'istanziazione dei controllori direttamente, o delle fabbriche (dove i controllori ricevono le loro dipendenze), Invokables, AbstractFactories. Ulteriori informazioni su ServiceManager qui

Utilizzo dell'invio della dipendenza / Inversione dei contenitori di controllo

È possibile utilizzare DiC per semplificare la gestione delle dipendenze per lo sviluppo di applicazioni rapide (RAD), ma aspettarsi ulteriori problemi di debug e di manutenzione lungo la strada se non si decide successivamente di iniettare direttamente le proprie dipendenze. Per evitare dolori maggiori, se hai intenzione di utilizzare DiC, usa il pattern RRR per creare i tuoi Controllers e popolarli con qualsiasi dipendenza.

Interfaccia contenitore PSR-11

Vedi link

    
risposta data 17.07.2017 - 22:03
fonte