Domanda

Comprendo i vantaggi dell'iniezione di dipendenza stessa. Prendiamo ad esempio la primavera. Comprendo anche i vantaggi di altre funzionalità di Spring come AOP, helper di diversi tipi, ecc. Mi chiedo solo, quali sono i vantaggi della configurazione XML come:

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

rispetto al semplice vecchio codice java come:

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

che è il debug più semplice, il tempo di compilazione è controllato e può essere compreso da chiunque conosca solo Java. Quindi qual è lo scopo principale di un framework di iniezione di dipendenza? (o un pezzo di codice che mostra i suoi vantaggi.)


UPDATE:
In caso di

IService myService;// ...
public void doSomething() {  
  myService.fetchData();
}

Come può il framework IoC indovinare quale implementazione di myService voglio essere iniettata se ce n'è più di una? Se esiste una sola implementazione di una determinata interfaccia e lascio che il contenitore IoC decida automaticamente di usarla, verrà interrotta dopo la visualizzazione di una seconda implementazione. E se esiste intenzionalmente una sola possibile implementazione di un'interfaccia, non è necessario iniettarla.

Sarebbe davvero interessante vedere un piccolo pezzo di configurazione per l'IoC che mostra i suoi vantaggi. Sto usando Spring da un po 'e non posso fornire un esempio del genere. E posso mostrare singole righe che dimostrano i vantaggi di ibernazione, dwr e altri framework che utilizzo.


AGGIORNAMENTO 2:
Mi rendo conto che la configurazione IoC può essere modificata senza ricompilare. È davvero una buona idea? Riesco a capire quando qualcuno vuole cambiare le credenziali del DB senza ricompilare - potrebbe non essere uno sviluppatore. Nella tua pratica, quanto spesso qualcun altro oltre allo sviluppatore cambia la configurazione IoC? Penso che per gli sviluppatori non ci sia nessuno sforzo per ricompilare quella particolare classe invece di cambiare la configurazione. E per i non sviluppatori probabilmente vorresti semplificargli la vita e fornire un file di configurazione più semplice.


AGGIORNAMENTO 3:

  

Configurazione esterna della mappatura tra le interfacce e le loro implementazioni concrete

Cosa c'è di così bello nel renderlo esteriore? Non rendi tutto il tuo codice esterno, mentre sicuramente puoi - basta inserirlo nel file ClassName.java.txt, leggere e compilare manualmente al volo - wow, hai evitato di ricompilare. Perché la compilazione dovrebbe essere evitata ?!

  

Risparmi tempo di codifica perché fornisci i mapping in modo dichiarativo, non in un codice procedurale

Capisco che a volte l'approccio dichiarativo fa risparmiare tempo. Ad esempio, dichiaro solo una volta che una mappatura tra una proprietà bean e una colonna DB e ibernazione utilizza questa mappatura durante il caricamento, il salvataggio, la creazione di SQL basato su HSQL, ecc. Qui è dove funziona l'approccio dichiarativo. Nel caso di Spring (nel mio esempio), la dichiarazione aveva più righe e aveva la stessa espressività del codice corrispondente. Se c'è un esempio in cui tale dichiarazione è più breve del codice, mi piacerebbe vederlo.

  

Il principio di inversione del controllo consente un facile test delle unità perché è possibile sostituire implementazioni reali con false (come sostituire il database SQL con uno in memoria)

Comprendo l'inversione dei vantaggi del controllo (preferisco chiamare il modello di progettazione discusso qui come Iniezione delle dipendenze, perché l'IoC è più generale - ci sono molti tipi di controllo e ne stiamo invertendo solo uno - controllo dell'inizializzazione) . Mi chiedevo perché qualcuno avesse mai bisogno di qualcosa di diverso da un linguaggio di programmazione per questo. Posso sicuramente sostituire le implementazioni reali con quelle false usando il codice. E questo codice esprimerà la stessa cosa della configurazione: inizializzerà semplicemente i campi con valori falsi.

mary = new FakeFemale();

Comprendo i vantaggi di DI. Non capisco quali vantaggi sono aggiunti dalla configurazione XML esterna rispetto alla configurazione del codice che fa lo stesso. Non penso che la compilazione debba essere evitata: compilo ogni giorno e sono ancora vivo. Penso che la configurazione di DI sia un cattivo esempio di approccio dichiarativo. La dichiarazione può essere utile se viene dichiarata una volta E viene utilizzata più volte in diversi modi, ad esempio hibernate cfg, dove la mappatura tra proprietà bean e colonna DB viene utilizzata per il salvataggio, il caricamento, la creazione di query di ricerca, ecc. La configurazione DI Spring può essere facilmente tradotta in la configurazione del codice, come all'inizio di questa domanda, non può? E viene utilizzato solo per l'inizializzazione del bean, non è vero? Il che significa che un approccio dichiarativo non aggiunge nulla qui, vero?

Quando dichiaro il mapping di ibernazione, do solo informazioni di ibernazione e funziona in base a esso - non dico cosa fare. In caso di primavera, la mia dichiarazione dice alla primavera esattamente cosa fare, quindi perché dichiararlo, perché non farlo e basta?


ULTIMO AGGIORNAMENTO:
Ragazzi, molte risposte mi dicono dell'iniezione di dipendenza, che so che è buona. La domanda riguarda lo scopo della configurazione DI invece dell'inizializzazione del codice: tendo a pensare che l'inizializzazione del codice sia più breve e più chiara. L'unica risposta che ho ricevuto finora alla mia domanda è che evita la ricompilazione, quando la configurazione cambia. Immagino che dovrei pubblicare un'altra domanda, perché è un grande segreto per me, perché la compilazione dovrebbe essere evitata in questo caso.

È stato utile?

Soluzione

Per quanto mi riguarda, uno dei motivi principali per utilizzare un IoC (e utilizzare la configurazione esterna) è attorno alle due aree di:

  • Test
  • Manutenzione della produzione

Test

Se dividi i test in 3 scenari (il che è abbastanza normale nello sviluppo su larga scala):

  1. Test unitari
  2. Test di integrazione
  3. Test della scatola nera

Quello che vorrai fare è per gli ultimi due scenari di test (Integrazione e scatola nera), non è ricompilare alcuna parte dell'applicazione.

Se uno qualsiasi dei tuoi scenari di test richiede di modificare la configurazione (ad esempio: utilizzare un altro componente per imitare un'integrazione bancaria o caricare una performance), questo può essere facilmente gestito (questo rientra nei vantaggi della configurazione del DI lato di un IoC però.

Inoltre, se l'app viene utilizzata in più siti (con diversa configurazione di server e componenti) o presenta una configurazione in evoluzione nell'ambiente live, è possibile utilizzare le fasi successive del test per verificare che l'app gestirà tali modifiche.

Produzione

Come sviluppatore non hai (e non dovresti) avere il controllo dell'ambiente di produzione (in particolare quando la tua app viene distribuita a più clienti o siti separati), questo per me è il vero vantaggio di usare entrambi un IoC e configurazione esterna, in quanto spetta al supporto di infrastruttura / produzione modificare e regolare l'ambiente live senza dover tornare agli sviluppatori e testare (costo maggiore quando tutto ciò che vogliono fare è spostare un componente).

Riepilogo

I principali vantaggi che derivano dalla configurazione esterna di un IoC derivano dal dare ad altri (non sviluppatori) il potere di configurare l'applicazione, nella mia esperienza questo è utile solo in un numero limitato di circostanze:

  • L'applicazione è distribuita su più siti / client in cui gli ambienti differiranno.
  • Controllo / input di sviluppo limitato sull'ambiente di produzione e sulla configurazione.
  • Scenari di test.

In pratica ho scoperto che anche quando si sviluppa qualcosa su cui si ha il controllo sull'ambiente su cui verrà eseguito, nel tempo è meglio dare a qualcun altro le capacità di modificare la configurazione:

  • Durante lo sviluppo non sai quando cambierà (l'app è così utile che la tua azienda la vende a qualcun altro).
  • Non voglio essere bloccato con la modifica del codice ogni volta che viene richiesta una leggera modifica che potrebbe essere gestita impostando e utilizzando un buon modello di configurazione.

Nota: l'applicazione si riferisce alla soluzione completa (non solo all'eseguibile), quindi tutti i file necessari per l'esecuzione dell'applicazione .

Altri suggerimenti

L'iniezione di dipendenza è uno stile di codifica che ha le sue radici nell'osservazione che la delega di oggetti è di solito un modello di progettazione più utile dell'ereditarietà di oggetti (vale a dire, l'oggetto ha una relazione è più utile rispetto all'oggetto è una relazione). Tuttavia, è necessario un altro ingrediente per far funzionare DI, quello della creazione di interfacce di oggetti. Combinando questi due potenti modelli di progettazione, gli ingegneri del software hanno capito rapidamente che potevano creare codice flessibile liberamente accoppiato e quindi è nato il concetto di Dependency Injection. Tuttavia, non è stato fino a quando la riflessione dell'oggetto non è diventata disponibile in alcuni linguaggi di alto livello che DI è davvero decollato. Il componente di riflessione è fondamentale per la maggior parte dei sistemi DI di oggi, perché gli aspetti davvero interessanti di DI richiedono la possibilità di selezionare a livello di programmazione oggetti e configurarli e iniettarli in altri oggetti utilizzando un sistema esterno e indipendente dagli oggetti stessi.

Un linguaggio deve fornire un buon supporto sia per le normali tecniche di programmazione orientate agli oggetti sia per le interfacce degli oggetti e la riflessione degli oggetti (ad esempio Java e C #). Sebbene sia possibile creare programmi utilizzando i pattern DI nei sistemi C ++, la sua mancanza di supporto per la riflessione all'interno del linguaggio proprio gli impedisce di supportare i server delle applicazioni e altre piattaforme DI e quindi limita l'espressività dei pattern DI.

Punti di forza di un sistema costruito usando modelli DI:

  1. Il codice DI è molto più facile da riutilizzare poiché la funzionalità "dipendente" viene estrapolata in interfacce ben definite, consentendo a oggetti separati la cui configurazione è gestita da una piattaforma applicativa adatta di essere collegati ad altri oggetti a piacimento.
  2. Il codice DI è molto più facile da testare. La funzionalità espressa dall'oggetto può essere testata in una scatola nera costruendo oggetti "finti" implementando le interfacce previste dalla logica dell'applicazione.
  3. Il codice DI è più flessibile. È un codice intrinsecamente vagamente accoppiato - ad un estremo. Ciò consente al programmatore di scegliere come gli oggetti sono collegati in base esclusivamente alle loro interfacce richieste da un lato e alle loro interfacce espresse dall'altro.
  4. La configurazione esterna (Xml) di oggetti DI significa che altri possono personalizzare il codice in direzioni impreviste.
  5. La configurazione esterna è anche una separazione del modello di preoccupazione in quanto tutti i problemi di inizializzazione e gestione dell'interdipendenza degli oggetti possono essere gestiti dal server delle applicazioni.
  6. Nota che per utilizzare il modello DI non è necessaria una configurazione esterna, per interconnessioni semplici un oggetto piccolo builder è spesso adeguato. C'è un compromesso nella flessibilità tra i due. Un oggetto builder non è un'opzione flessibile come un file di configurazione visibile esternamente. Lo sviluppatore del sistema DI deve soppesare i vantaggi della flessibilità rispetto alla convenienza, avendo cura che il controllo su piccola scala e la grana fine sulla costruzione degli oggetti, come espresso in un file di configurazione, possa aumentare i costi di confusione e manutenzione lungo la linea.

Sicuramente il codice DI sembra più ingombrante, gli svantaggi di avere tutti quei file XML che configurano gli oggetti da iniettare in altri oggetti sembrano difficili. Questo è, tuttavia, il punto dei sistemi DI. La tua capacità di mescolare e abbinare oggetti di codice come una serie di impostazioni di configurazione ti consente di costruire sistemi complessi utilizzando codice di terze parti con una codifica minima da parte tua.

L'esempio fornito nella domanda tocca semplicemente la superficie del potere espressivo che può fornire una libreria di oggetti DI adeguatamente fattorizzata. Con un po 'di pratica e molta autodisciplina, la maggior parte dei professionisti DI scopre di poter costruire sistemi che hanno una copertura del 100% del codice dell'applicazione. Questo solo punto è straordinario. Questa non è una copertura di test al 100% di una piccola applicazione di poche centinaia di righe di codice, ma una copertura di test al 100% di applicazioni che comprendono centinaia di migliaia di righe di codice. Non riesco a descrivere qualsiasi altro modello di progettazione che fornisca questo livello di testabilità.

Hai ragione nel dire che un'applicazione di soli 10 decine di righe di codice è più semplice da comprendere rispetto a diversi oggetti più una serie di file di configurazione XML. Tuttavia, come con i modelli di progettazione più potenti, i vantaggi si ottengono mentre si continuano ad aggiungere nuove funzionalità al sistema.

In breve, le applicazioni basate su DI su larga scala sono sia più facili da eseguire il debug sia da comprendere. Mentre la configurazione Xml non è "verifica tempo di compilazione", tutti i servizi applicativi di cui questo autore è a conoscenza forniranno allo sviluppatore messaggi di errore se tentano di iniettare un oggetto con un'interfaccia incompatibile in un altro oggetto. E la maggior parte fornisce una funzione di "controllo" che copre tutte le configurazioni di oggetti noti. Ciò è facile e rapido verificando che l'oggetto A da iniettare A implementi l'interfaccia richiesta dall'oggetto B per tutte le iniezioni di oggetti configurate.

Questa è una domanda un po 'carica, ma tendo a concordare sul fatto che enormi quantità di configurazione XML non equivalgono davvero a molti vantaggi. Mi piace che le mie applicazioni siano le più leggere possibili sulle dipendenze, compresi i quadri pesanti.

Semplificano il codice molte volte, ma hanno anche un sovraccarico di complessità che rende piuttosto difficile individuare i problemi (ho visto questi problemi in prima persona, e Java dritto mi farebbe molto più comodo occuparmi di) .

Immagino che dipenda un po 'dallo stile e da cosa ti senti a tuo agio ... ti piace far volare la tua soluzione e avere il vantaggio di conoscerla a fondo, o affidarti a soluzioni esistenti che potrebbero rivelarsi difficili quando la configurazione non è giusta? È tutto un compromesso.

Tuttavia, la configurazione XML è un po 'una mia piccola pisciata ... Cerco di evitarlo a tutti i costi.

Ogni volta che puoi modificare il codice in dati, fai un passo nella giusta direzione.

Codificare qualsiasi cosa come dati significa che il codice stesso è più generale e riutilizzabile. Significa anche che i tuoi dati possono essere specificati in una lingua che si adatta esattamente.

Inoltre, un file XML può essere letto in una GUI o in qualche altro strumento e può essere facilmente manipolato in modo pragmatico. Come faresti con l'esempio di codice?

Ricerco costantemente cose che la maggior parte delle persone implementerebbe come codice nei dati, rende il codice lasciato MOLTO più pulito. Trovo inconcepibile che le persone creino un menu nel codice piuttosto che come dati - dovrebbe essere ovvio che farlo nel codice è semplicemente sbagliato a causa del bollettino.

La ragione per usare un contenitore DI è che non devi avere un miliardo di proprietà preconfigurate nel tuo codice che sono semplicemente getter e setter. Vuoi davvero codificare tutti quelli con la nuova X ()? Certo, puoi avere un valore predefinito, ma il contenitore DI consente la creazione di singleton che è estremamente facile e ti consente di concentrarti sui dettagli del codice, non sul compito vario di inizializzarlo.

Ad esempio, Spring ti consente di implementare l'interfaccia InitializingBean e aggiungere un metodo afterPropertiesSet (puoi anche specificare un metodo "quot" per evitare di accoppiare il tuo codice a Spring). Questi metodi ti permetteranno di assicurarti che qualsiasi interfaccia specificata come campo nella tua istanza di classe sia configurata correttamente all'avvio, e quindi non dovrai più controllare nulla i tuoi getter e setter (supponendo che tu permetta ai tuoi singleton di rimanere thread-safe ).

Inoltre, è molto più semplice eseguire complesse inizializzazioni con un contenitore DI anziché eseguirle da soli. Ad esempio, assisto all'uso di XFire (non CeltiXFire, utilizziamo solo Java 1.4). L'app utilizzava Spring, ma sfortunatamente utilizzava il meccanismo di configurazione services.xml di XFire. Quando una raccolta di elementi doveva dichiarare che aveva ZERO o più istanze invece di UNA o più istanze, dovevo sovrascrivere parte del codice XFire fornito per questo particolare servizio.

Esistono alcuni valori predefiniti XFire definiti nello schema dei bean Spring. Quindi, se stessimo usando Spring per configurare i servizi, i bean avrebbero potuto essere usati. Invece, quello che è successo è stato che dovevo fornire un'istanza di una classe specifica nel file services.xml invece di usare i bean. Per fare ciò, dovevo fornire il costruttore e impostare i riferimenti dichiarati nella configurazione di XFire. Il vero cambiamento che dovevo apportare richiedeva il sovraccarico di una singola classe.

Ma, grazie al file services.xml, ho dovuto creare quattro nuove classi, impostando i loro valori predefiniti in base ai loro valori predefiniti nei file di configurazione di Spring nei loro costruttori. Se fossimo stati in grado di utilizzare la configurazione di Spring, avrei potuto semplicemente dichiarare:

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

Invece, sembrava più così:

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

Quindi il risultato netto è che quattro classi Java aggiuntive, per lo più inutili, dovevano essere aggiunte alla base di codice per ottenere l'effetto ottenuto da una classe aggiuntiva e da alcune semplici informazioni sul contenitore delle dipendenze. Questa non è l'eccezione "che dimostra la regola", questa è la regola ... la gestione delle stranezze nel codice è molto più chiara quando le proprietà sono già fornite in un contenitore DI e le stai semplicemente cambiando per adattarle a una situazione speciale , che accade più spesso.

Ho la tua risposta

Esistono ovviamente dei compromessi in ogni approccio, ma i file di configurazione XML esterni sono utili per lo sviluppo aziendale in cui vengono utilizzati sistemi di compilazione per compilare il codice e non l'IDE. Utilizzando il sistema di compilazione, potresti voler inserire determinati valori nel tuo codice, ad esempio la versione della build (che potrebbe essere doloroso dover aggiornare manualmente ogni volta che compili). Il dolore è maggiore quando il tuo sistema di compilazione estrae il codice da alcuni sistemi di controllo della versione. La modifica di valori semplici in fase di compilazione richiederebbe la modifica di un file, il commit, la compilazione e quindi il ripristino ogni volta per ogni modifica. Queste non sono modifiche che desideri impegnare nel controllo della versione.

Altri utili casi d'uso riguardanti il ??sistema di compilazione e le configurazioni esterne:

  • iniettando stili / fogli di stile per una singola base di codice per build diverse
  • iniettando diversi set di contenuti dinamici (o riferimenti a essi) per la tua singola base di codice
  • iniettando il contesto di localizzazione per build / client diversi
  • modifica di un URI del servizio web in un server di backup (quando quello principale non funziona)

Aggiornamento: Tutti gli esempi sopra menzionati riguardavano cose che non richiedevano necessariamente dipendenze dalle classi. Ma puoi facilmente creare casi in cui sono necessari sia un oggetto complesso che l'automazione, ad esempio:

  • Immagina di avere un sistema in cui monitorava il traffico del tuo sito web. A seconda del numero di utenti simultanei, attiva / disattiva un meccanismo di registrazione. Forse mentre il meccanismo è spento, un oggetto stub viene messo al suo posto.
  • Immagina di avere un sistema di web conferencing in cui, a seconda del numero di utenti, vuoi cambiare la possibilità di fare P2P a seconda del numero di partecipanti

Non è necessario ricompilare il codice ogni volta che si modifica qualcosa nella configurazione. Semplificherà l'implementazione e la manutenzione del programma. Ad esempio, è possibile scambiare un componente con un altro con solo 1 modifica nel file di configurazione.

Puoi inserire una nuova implementazione per la fidanzata. In questo modo è possibile iniettare nuova femmina senza ricompilare il codice.

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(Quanto sopra presuppone che Female e HotFemale implementino la stessa interfaccia GirlfFriend)

Nel mondo .NET, la maggior parte dei framework IoC fornisce sia la configurazione XML che Code.

StructureMap e Ninject, ad esempio, utilizzano interfacce fluide per configurare i contenitori. Non sei più costretto a utilizzare i file di configurazione XML. Spring, che esiste anche in .NET, si affida fortemente ai file XML poiché è la sua interfaccia di configurazione principale storica, ma è ancora possibile configurare i contenitori a livello di codice.

Facilità di combinare configurazioni parziali in una configurazione completa finale.

Ad esempio, nelle applicazioni Web, il modello, la vista e i controller sono in genere specificati in file di configurazione separati. Utilizzare l'approccio dichiarativo, è possibile caricare, ad esempio:

  UI-context.xml
  Model-context.xml
  Controller-context.xml

Oppure carica con un'interfaccia utente diversa e alcuni controller extra:

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

Per fare lo stesso nel codice è necessaria un'infrastruttura per combinare configurazioni parziali. Non impossibile da fare nel codice, ma sicuramente più facile da usare usando un framework IoC.

Spesso, il punto importante è chi sta cambiando la configurazione dopo che il programma è stato scritto. Con la configurazione nel codice, supponi implicitamente che la persona che lo modifica abbia le stesse competenze e accesso al codice sorgente ecc. Dell'autore originale.

Nei sistemi di produzione è molto pratico estrarre alcuni sottogruppi di impostazioni (ad es. età nel tuo esempio) in file XML e consentire ad es. amministratore di sistema o supporto personale per modificare il valore senza fornire loro il pieno potere sul codice sorgente o altre impostazioni - o semplicemente per isolarli dalle complessità.

Da una prospettiva di primavera posso darti due risposte.

Innanzitutto la configurazione XML non è l'unico modo per definire la configurazione. Molte cose possono essere configurate usando le annotazioni e le cose che devono essere fatte con XML sono la configurazione per il codice che non stai scrivendo comunque, come un pool di connessioni che stai usando da una libreria. La primavera 3 include un metodo per definire la configurazione DI usando Java simile alla configurazione DI arrotolata a mano nel tuo esempio. Quindi usare Spring non significa che devi usare un file di configurazione basato su XML.

Secondariamente Spring è molto più di un semplice framework DI. Ha molte altre funzionalità tra cui la gestione delle transazioni e AOP. La configurazione XML Spring mescola insieme tutti questi concetti. Spesso nello stesso file di configurazione sto specificando dipendenze di bean, impostazioni di transazione e aggiungendo bean con ambito di sessione che sono stati effettivamente gestiti utilizzando AOP in background. Trovo che la configurazione XML offra un posto migliore per gestire tutte queste funzionalità. Sento anche che la configurazione basata su annotazione e la configurazione XML si adattano meglio rispetto alla configurazione basata su Java.

Ma vedo il tuo punto e non c'è niente di sbagliato nel definire la configurazione dell'iniezione di dipendenza in Java. Normalmente lo faccio da solo nei test unitari e quando lavoro su un progetto abbastanza piccolo da non aver aggiunto un framework DI. Normalmente non specifico la configurazione in Java perché per me questo è il tipo di codice idraulico che sto cercando di evitare di scrivere quando ho scelto di usare Spring. Questa è una preferenza, tuttavia, non significa che la configurazione XML sia superiore alla configurazione basata su Java.

Spring ha anche un caricatore di proprietà. Utilizziamo questo metodo per impostare variabili dipendenti dall'ambiente (ad es. Sviluppo, test, accettazione, produzione, ...). Potrebbe essere ad esempio la coda da ascoltare.

Se non vi è alcun motivo per cui la proprietà cambierebbe, non esiste alcun motivo per configurarla in questo modo.

Il tuo caso è molto semplice e quindi non necessita di un contenitore IoC (Inversion of Control) come Spring. D'altra parte, quando "programmi a interfacce, non implementazioni" (che è una buona pratica in OOP), puoi avere un codice come questo:

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

(nota che il tipo di myService è IService, un'interfaccia, non un'implementazione concreta). Ora può essere utile lasciare che il tuo contenitore IoC fornisca automaticamente l'istanza concreta corretta di IService durante l'inizializzazione: quando hai molte interfacce e molte implementazioni, può essere complicato farlo a mano. I principali vantaggi di un contenitore IoC (framework di iniezione delle dipendenze) sono:

  • Configurazione esterna della mappatura tra le interfacce e le loro implementazioni concrete
  • Il contenitore IoC gestisce alcuni problemi delicati come la risoluzione di complicati grafici delle dipendenze, la gestione della durata dei componenti, ecc.
  • Risparmi tempo di codifica perché fornisci i mapping in modo dichiarativo, non in un codice procedurale
  • Il principio di inversione del controllo consente un facile test delle unità perché è possibile sostituire implementazioni reali con false (come sostituire il database SQL con uno in memoria)

L'inizializzazione in un file di configurazione XML semplifica il lavoro di debug / adattamento con un client che ha la tua app distribuita sui loro computer. (Perché non richiede la ricompilazione + la sostituzione di file binari)

Uno dei motivi più interessanti è il " Principio di Hollywood " ;: don ' Non chiamarci, ti chiameremo. Non è necessario un componente per eseguire ricerche su altri componenti e servizi stessi; invece vengono forniti automaticamente. In Java, ciò significa che non è più necessario eseguire ricerche JNDI all'interno del componente.

È anche molto più semplice testare un componente in modo isolato: invece di dargli un'implementazione effettiva dei componenti di cui ha bisogno, si usano semplicemente beffe (eventualmente generate automaticamente).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top