Quali sono i vantaggi dei contenitori di inserimento delle dipendenze?


104

Comprendo i vantaggi dell'iniezione di dipendenza stessa. Prendiamo ad esempio la primavera. Capisco anche i vantaggi di altre funzionalità di Spring come AOP, helper di diverso tipo, 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 è più facile da eseguire il debug, il tempo di compilazione controllato e può essere compreso da chiunque conosca solo java. Allora qual è lo scopo principale di un framework di inserimento delle dipendenze? (o un pezzo di codice che mostra i suoi vantaggi.)


AGGIORNAMENTO:
In caso di

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

Come può il framework IoC indovinare quale implementazione di myService desidero venga iniettata se ce n'è più di una? Se è presente 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 c'è intenzionalmente solo una possibile implementazione di un'interfaccia, non è necessario iniettarla.

Sarebbe davvero interessante vedere un piccolo pezzo di configurazione per IoC che mostra i suoi vantaggi. Uso Spring da un po 'e non posso fornire un simile esempio. E posso mostrare singole righe che dimostrano i vantaggi di hibernate, 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 ricompilarlo: potrebbe non essere uno sviluppatore. Nella tua pratica, con che frequenza qualcun altro diverso dallo sviluppatore cambia la configurazione IoC? Penso che per gli sviluppatori non ci sia alcuno sforzo per ricompilare quella particolare classe invece di cambiare la configurazione. E per i non sviluppatori probabilmente vorrai semplificargli la vita e fornire un file di configurazione più semplice.


AGGIORNAMENTO 3:

Configurazione esterna della mappatura tra interfacce e loro implementazioni concrete

Cosa c'è di così buono nel renderlo extenal? 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é si dovrebbe evitare la compilazione ?!

Risparmi tempo di codifica perché fornisci le mappature in modo dichiarativo, non in un codice procedurale

Capisco che l'approccio a volte dichiarativo fa risparmiare tempo. Ad esempio, dichiaro solo una volta che una mappatura tra una proprietà del bean e una colonna DB e hibernate utilizza questa mappatura durante il caricamento, il salvataggio, la creazione di SQL basato su HSQL, ecc. È qui che 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 le implementazioni reali con quelle false (come la sostituzione del database SQL con uno in memoria)

Capisco l'inversione dei vantaggi del controllo (preferisco chiamare il modello di progettazione discusso qui come Dependency Injection, perché IoC è più generale: ci sono molti tipi di controllo e ne stiamo invertendo solo uno: controllo dell'inizializzazione). Stavo chiedendo perché qualcuno abbia 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à solo i campi con valori falsi.

mary = new FakeFemale();

Capisco i vantaggi di DI. Non capisco quali vantaggi vengono aggiunti dalla configurazione XML esterna rispetto alla configurazione del codice che fa lo stesso. Non credo che la compilazione debba essere evitata: compilo tutti i giorni 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 AND viene utilizzata molte volte in modi diversi, come hibernate cfg, dove la mappatura tra la proprietà del bean e la colonna DB viene utilizzata per il salvataggio, il caricamento, la creazione di query di ricerca, ecc. La configurazione di Spring DI può essere facilmente tradotta in configurare il codice, come all'inizio di questa domanda, non è vero? Ed è usato solo per l'inizializzazione dei bean, non è vero? Il che significa che un approccio dichiarativo non aggiunge nulla qui, vero?

Quando dichiaro la mappatura di ibernazione, fornisco solo alcune informazioni di ibernazione e funziona in base ad essa - non gli dico cosa fare. In caso di primavera, la mia dichiarazione dice alla primavera esattamente cosa fare, quindi perché dichiararla, perché non farlo e basta?


ULTIMO AGGIORNAMENTO:
Ragazzi, molte risposte mi dicono sull'iniezione di dipendenza, che SO È BENE. La domanda riguarda lo scopo della configurazione DI invece di inizializzare il codice: tendo a pensare che l'inizializzazione del codice sia più breve e più chiara. L'unica risposta che ho ottenuto 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é in questo caso la compilazione dovrebbe essere evitata.


21
Finalmente qualcuno ha avuto il coraggio di porre questa domanda. Perché in effetti dovresti evitare la ricompilazione quando la tua implementazione cambia al costo di sacrificare (o almeno degradare) il supporto di tool / IDE?
Christian Klauser

3
Sembra che il titolo non sia corretto. L'autore ha detto che i contenitori IOC vanno bene, ma sembra avere problemi con l'utilizzo di XML config invece di configurare tramite codice (e anche abbastanza equo). Suggerirei forse "Quali sono i vantaggi della configurazione dei contenitori IOC tramite XML o altri approcci non di codice?"
Orion Edwards

Gli esempi di @Orion che ho fornito (con maschio e femmina) non richiedono alcun contenitore IOC. Sto bene con IOC; l'utilizzo del container sia che sia configurato utilizzando XML o meno, è ancora una questione aperta per me.
Pavel Feldman

@ Orion 2: Anche se utilizzo una qualche forma di IOC nella maggior parte dei progetti, alcuni di essi traggono vantaggio dal contenitore IOC tanto quanto traggono vantaggio dal contenitore di assegnazione variabile o dal contenitore di istruzione If - spesso solo il linguaggio è sufficiente per me. Non ho problemi a ricompilare i progetti su cui sto lavorando e avere il codice di inizializzazione dev / test / production opportunamente separato. Quindi per me il titolo va bene.
Pavel Feldman

Vedo problemi con il campione. Uno dei principi è Inject services, not data
Jacek Cz

Risposte:


40

Per me uno dei motivi principali per utilizzare un IoC (e fare uso di configurazione esterna) è intorno alle due aree di:

  • analisi
  • Manutenzione della produzione

analisi

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

  1. Test di unità
  2. Test d'integrazione
  3. Test della scatola nera

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

Se uno qualsiasi degli scenari di test richiede di modificare la configurazione (ad esempio: utilizzare un altro componente per simulare un'integrazione bancaria o eseguire un carico sulle prestazioni), questo può essere facilmente gestito (questo rientra nei vantaggi della configurazione del lato DI di un IoC però.

Inoltre, se la tua app viene utilizzata su più siti (con diverse configurazioni di server e componenti) o ha una configurazione mutevole nell'ambiente live, puoi utilizzare le fasi successive del test per verificare che l'app gestirà tali modifiche.

Produzione

In qualità di 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 dell'utilizzo sia di una configurazione IoC che esterna , poiché spetta al supporto dell'infrastruttura / produzione modificare e adattare l'ambiente live senza dover tornare dagli sviluppatori e attraverso il test (costo più elevato quando tutto ciò che vogliono è spostare un componente).

Sommario

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

  • L'applicazione viene distribuita su più siti / client in cui gli ambienti saranno diversi.
  • Controllo / input di sviluppo limitati sull'ambiente di produzione e sulla configurazione.
  • Scenari di prova.

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à per 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 avrebbe potuto 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 .


14

L'inserimento delle dipendenze è uno stile di codifica che ha le sue radici nell'osservazione che la delega degli oggetti è solitamente un modello di progettazione più utile dell'ereditarietà degli oggetti (cioè, l'oggetto ha una relazione è più utile dell'oggetto è una relazione). Un altro ingrediente è necessario, tuttavia, affinché DI funzioni, quello di creare interfacce a oggetti. Combinando questi due potenti modelli di progettazione, gli ingegneri del software si sono presto resi conto che potevano creare codice flessibile e liberamente accoppiato e quindi è nato il concetto di Dependency Injection. Tuttavia, è stato solo quando la riflessione dell'oggetto è diventata disponibile in alcuni linguaggi di alto livello che DI ha davvero preso piede. La componente riflessione è fondamentale per la maggior parte di oggi

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

Punti di forza di un sistema costruito utilizzando modelli DI:

  1. Il codice DI è molto più facile da riutilizzare poiché la funzionalità "dipendente" viene estrapolata in interfacce ben definite, consentendo di collegare oggetti separati la cui configurazione è gestita da una piattaforma applicativa adatta ad altri oggetti a piacere.
  2. Il codice DI è molto più facile da testare. La funzionalità espressa dall'oggetto può essere testata in una scatola nera costruendo oggetti "fittizi" che implementano le interfacce previste dalla logica dell'applicazione.
  3. Il codice DI è più flessibile. È un codice innatamente debolmente accoppiato - fino all'estremo. Ciò consente al programmatore di scegliere come collegare gli oggetti in base esclusivamente alle interfacce richieste da un lato e alle interfacce espresse dall'altro.
  4. La configurazione esterna (Xml) degli 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 degli oggetti e di gestione dell'interdipendenza degli oggetti possono essere gestiti dal server delle applicazioni.
  6. Si noti che la configurazione esterna non è richiesta per utilizzare il pattern DI, per le interconnessioni semplici è spesso sufficiente un piccolo oggetto builder. C'è un compromesso in termini di 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 praticità, facendo attenzione che il controllo su piccola scala e fine sulla costruzione dell'oggetto, espresso in un file di configurazione, possa aumentare la confusione ei costi di manutenzione su tutta 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 di forza dei sistemi DI. La tua capacità di combinare e abbinare oggetti di codice come una serie di impostazioni di configurazione ti consente di creare 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 una libreria di oggetti DI correttamente fattorizzata può fornire. Con un po 'di pratica e molta autodisciplina, la maggior parte dei professionisti di DI scopre di poter costruire sistemi che hanno una copertura del 100% del codice dell'applicazione. Questo solo punto è straordinario. Non si tratta di una copertura di prova del 100% di una piccola applicazione di poche centinaia di righe di codice, ma di una copertura di prova del 100% di applicazioni che comprendono centinaia di migliaia di righe di codice. Non sono in grado di descrivere qualsiasi altro modello di progettazione che fornisca questo livello di testabilità.

Hai ragione in quanto un'applicazione di soli 10 secondi di righe di codice è più facile da capire rispetto a diversi oggetti più una serie di file di configurazione XML. Tuttavia, come con i modelli di progettazione più potenti, i vantaggi si riscontrano man mano che si continuano ad aggiungere nuove funzionalità al sistema.

In breve, le applicazioni basate su DI su larga scala sono più facili da eseguire il debug e più facili da capire. Sebbene la configurazione Xml non sia "verificata in fase di compilazione", tutti i servizi applicativi di cui è a conoscenza questo autore 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 conosciuti. Ciò è possibile in modo semplice e rapido verificando che l'oggetto A da iniettare implementa l'interfaccia richiesta dall'oggetto B per tutte le iniezioni di oggetti configurati.


4
comprendere i vantaggi di DI. Non capisco quali vantaggi vengono aggiunti dalla configurazione XML esterna rispetto alla configurazione del codice che fa lo stesso. I vantaggi che hai menzionato sono forniti da DI design pattern. La domanda riguardava i vantaggi della configurazione DI rispetto al semplice codice di inizializzazione.
Pavel Feldman,

> Anche la configurazione esterna è una separazione ... La separazione della configurazione è il cuore di DI, il che è positivo. E può essere rimosso utilizzando il codice di inizializzazione. Cosa aggiunge cfg rispetto all'inizializzazione del codice? Per me sembra che ogni riga di cfg abbia la corrispondente riga di codice di inizializzazione.
Pavel Feldman

7

Questa è una domanda un po 'complicata, ma tendo a concordare sul fatto che enormi quantità di configurazione xml non danno davvero molto beneficio. Mi piace che le mie applicazioni siano il più leggere possibile sulle dipendenze, inclusi i framework pesanti.

Semplificano il codice un sacco di volte, ma hanno anche un sovraccarico di complessità che rende piuttosto difficile rintracciare i problemi (ho visto tali problemi in prima persona, e Java diretto mi sentirei molto più a mio agio nel trattare).

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

Tuttavia, la configurazione XML è un po 'una delle mie preoccupazioni ... Cerco di evitarlo a tutti i costi.


5

Ogni volta che puoi modificare il tuo codice in dati, stai facendo 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 facilmente manipolato in modo pragmatico. Come lo faresti con l'esempio di codice?

Tengo costantemente conto delle cose che la maggior parte delle persone implementerebbe come codice nei dati, rendendo il codice 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 boilerplate.


ha senso, non ci ho pensato in questa prospettiva
Pavel Feldman

7
poi di nuovo, le persone spesso vanno dall'altra parte e cercano di inserire la logica nei dati, il che significa semplicemente che
finisci

@Casebash Questo è un punto di vista interessante - sarei incredibilmente interessato a un esempio. Trovo che tutto ciò che posso spostare nei dati aiuta. Trovo anche che se faccio solo quello che dici, la lingua è effettivamente migliorata perché è un DSL, ma anche in questo caso ci vuole una seria giustificazione per creare una lingua completamente nuova.
Bill K,

1
"Ogni volta che puoi modificare il codice in dati, fai un passo nella giusta direzione." Benvenuti nell'anti-pattern di Soft Coding.
Raedwald

@Raedwald Quello di cui stai parlando è l'esternalizzazione, che può essere davvero difficile se non sai cosa stai facendo (e il motivo per cui qualcuno di incompetente l'ha provato, ha fallito e l'ha chiamato un anti-pattern) Esempi più positivi sarebbero Injection, Iterators , quasi tutto ciò che contiene annotazioni, tutto ciò che viene inizializzato con gli array. La maggior parte delle grandi strutture di programmazione sono un tentativo di separare le differenze nel codice e combinare ciò che resta, guidandolo con qualcosa che può essere raggruppato e gestito meglio.
Bill K

3

Il motivo per utilizzare un contenitore DI è che non è necessario disporre di un miliardo di proprietà preconfigurate nel 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 semplice e ti consente di concentrarti sui dettagli del codice, non sul compito miscellaneo di inizializzarlo.

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

Inoltre, è molto più facile eseguire inizializzazioni complesse con un contenitore DI invece di eseguirle da soli. Ad esempio, assisto nell'utilizzo di XFire (non CeltiXFire, usiamo 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 di avere ZERO o più istanze invece di UNA o più istanze, dovevo sovrascrivere parte del codice XFire fornito per questo particolare servizio.

Ci sono alcune impostazioni predefinite di XFire definite 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 ho dovuto 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 fare richiedeva di sovraccaricare 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 Spring, avrei potuto semplicemente affermare:

<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ù simile a questo:

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 è stato necessario aggiungere quattro classi Java aggiuntive, per lo più inutili, al codice base per ottenere l'effetto ottenuto da una classe aggiuntiva e da alcune semplici informazioni sul contenitore delle dipendenze. Questa non è "l'eccezione che conferma la regola", questa È la regola ... gestire le stranezze nel codice è molto più semplice quando le proprietà sono già fornite in un contenitore DI e le stai semplicemente modificando per adattarle a una situazione speciale, cosa che accade il più delle volte.


3

Ho la tua risposta

Ovviamente ci sono dei compromessi in ogni approccio, ma i file di configurazione XML esternalizzati 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 problema è maggiore quando il sistema di compilazione estrae il codice da un sistema 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 applicare al controllo della versione.

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

  • iniettare stili / fogli di stile per una singola base di codice per build diverse
  • iniettare diversi set di contenuti dinamici (o riferimenti ad essi) per la tua singola base di codice
  • inserimento del contesto di localizzazione per build / client differenti
  • cambiare l'URI di un servizio web in un server di backup (quando quello principale non funziona)

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

  • Immagina di avere un sistema in cui monitora 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, desideri cambiare la possibilità di fare P2P a seconda del numero di partecipanti

+1 per evidenziare l'aspetto aziendale in alto. Testare un codice legacy scritto male a volte può essere un incubo lungo giorni.
Richard Le Mesurier

2

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


distribuzione? probabilmente ... manutenzione della distribuzione? probabilmente ... manutenzione del codice? Tendo a pensare di no ... il debug attraverso i framework tende ad essere un grande mal di testa, e i pojo sono molto più facili da gestire a questo proposito.
Mike Stone,

1
Mike, non ho detto niente sul codice. Sappiamo tutti che la configurazione XML fa schifo :)
aku

Hmm .. quanto spesso cambi i componenti senza ricompilare e per cosa? Capisco se qualcuno cambia le credenziali del DB e non vuole ricompilare il programma - potrebbe non essere lui a svilupparlo. Ma difficilmente riesco a immaginare qualcuno diverso dallo sviluppatore che cambia la configurazione della molla
Pavel Feldman,

Pavel di solito questa situazione si verifica quando devi distribuire il programma a centinaia di client. In tale situazione è molto più facile cambiare la configurazione piuttosto che distribuire una nuova versione del prodotto. Hai ragione a dire sugli sviluppatori. Di solito lo sviluppatore crea un nuovo cfg e l'amministratore lo distribuisce.
aku

2

Puoi inserire una nuova implementazione per la ragazza. Quindi una nuova femmina può essere iniettata 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)


Perché le modifiche logiche senza ricompilazione sono considerate una buona idea?
Pavel Feldman,

Sicuramente posso fare HotFemale jane = new HotFmale (); jane.setAge (19); john.setGirlfriend (jane); Quindi l'unica differenza è che cfg può essere modificato senza ricompilare? Sembra essere una risposta comune quando si parla di primavera. Perché?! Perché è bene evitare la compilazione?
Pavel Feldman

Bene, posso testare il codice meglio posso Mock the Female Object.
Paul Whelan,

@Pavel Feldman: perché se hai già l'app distribuita sul client è più facile.
Andrei Rînea

1

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

StructureMap e Ninject, ad esempio, utilizzano interfacce fluenti per configurare i contenitori. Non sei più costretto a utilizzare i file di configurazione XML. Spring, che esiste anche in .NET, fa molto affidamento sui file XML poiché è la sua interfaccia di configurazione principale storica, ma è ancora possibile configurare i contenitori a livello di programmazione.


È fantastico poter finalmente usare il codice per quello che intendeva essere usato :) Ma perché ho bisogno di qualcosa di diverso dal linguaggio di programmazione per fare queste cose?
Pavel Feldman

Penso che sia perché XML consente modifiche al runtime, o almeno, modifiche alla configurazione senza dover ricompilare il progetto.
Romain Verdier

1

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

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

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

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

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

Per fare lo stesso nel codice è necessaria un'infrastruttura per la combinazione di configurazioni parziali. Non impossibile da fare nel codice, ma sicuramente più facile da fare utilizzando un framework IoC.


1

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

Nei sistemi di produzione è molto pratico estrarre alcuni sottoinsiemi di impostazioni (ad esempio età nell'esempio) in un file XML e consentire ad esempio all'amministratore di sistema o al personale di supporto di modificare il valore senza dare loro il pieno potere sul codice sorgente o altre impostazioni - o semplicemente isolarli dalle complessità.


Questo è un punto valido, ma la configurazione della molla spesso tende ad essere piuttosto complessa. Sebbene sia facile cambiare età, l'amministratore di sistema deve ancora occuparsi di file xml di grandi dimensioni che non è necessario comprendere completamente. Non è meglio estrarre la parte che dovrebbe essere configurata in qualcosa di ancora più semplice, rispetto alla configurazione XML di primavera? Come il file delle proprietà, con una sola riga "age = 23" e non lasciare che l'amministratore modifichi altri dettagli, come i nomi delle classi, ecc., Che richiedono la conoscenza della struttura interna del programma.
Pavel Feldman

Recentemente stavo lavorando a un progetto che aveva un misto di codice Java e XSLT. Il team era un misto di persone che erano forti in Java (e forse meno a loro agio nel lavorare con XML e XSLT); e persone che erano molto brave a lavorare con XML e XSLT (e meno a loro agio con Java). Poiché la configurazione sarebbe stata gestita dal secondo gruppo, aveva senso usare Spring e avere configurazioni XML. In altre parole, Spring ha risolto un problema di divisione del lavoro nel team. Non ha risolto un problema "tecnico"; nel senso che la configurazione avrebbe potuto essere eseguita altrettanto facilmente con codice Java.
Dawood ibn Kareem

Quando il "personale di supporto" saprebbe qualcosa sulla necessità di modificare alcune classi create all'interno di un contenitore di inserimento delle dipendenze? Davvero partendo dal presupposto che sia compito di uno sviluppatore farlo?
Jimbo

Questo è esattamente il motivo per cui l'estrazione dei valori di configurazione (ad esempio l'URL del sistema con cui si integra) ha senso: il personale di supporto modifica il file delle proprietà o (nel peggiore dei casi) il file XML, la classe Java compilata rimane la stessa.
Miro A.

1

Da una prospettiva primaverile posso darvi due risposte.

Innanzitutto la configurazione XML non è l'unico modo per definire la configurazione. La maggior parte delle cose può essere configurata 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. Spring 3 include un metodo per definire la configurazione DI utilizzando Java simile alla configurazione DI rolled a mano nel tuo esempio. Quindi usare Spring non significa che devi usare un file di configurazione basato su XML.

In secondo luogo Spring è molto più di un semplice framework DI. Ha molte altre funzionalità tra cui la gestione delle transazioni e AOP. La configurazione Spring XML combina tutti questi concetti insieme. Spesso nello stesso file di configurazione sto specificando le dipendenze dei bean, le impostazioni delle transazioni e aggiungendo i 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à. Ritengo inoltre che la configurazione basata su annotazioni e la configurazione XML aumentino meglio rispetto alla configurazione basata su Java.

Ma capisco il tuo punto e non c'è niente di sbagliato nel definire la configurazione di inserimento delle dipendenze in Java. Normalmente lo faccio io stesso 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 è 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.


0

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

Se non c'è motivo per cui la proprietà cambierebbe, non c'è nemmeno motivo per configurarla in questo modo.


0

Il tuo caso è molto semplice e quindi non necessita di un contenitore IoC (Inversion of Control) come Spring. D'altra parte, quando "programmi su 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 interfacce e loro implementazioni concrete
  • Il contenitore IoC gestisce alcuni problemi delicati come la risoluzione di complicati grafici di dipendenza, la gestione della durata dei componenti, ecc.
  • Risparmi tempo di codifica perché fornisci le mappature in modo dichiarativo, non in un codice procedurale
  • Il principio di inversione del controllo consente un facile test delle unità perché è possibile sostituire le implementazioni reali con quelle false (come la sostituzione del database SQL con uno in memoria)

0

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


-2

Uno dei motivi più interessanti è il " principio di Hollywood ": non chiamateci, vi chiameremo noi. Non è necessario che un componente effettui ricerche su altri componenti e servizi; invece gli vengono forniti automaticamente. In Java, ciò significa che non è più necessario eseguire ricerche JNDI all'interno del componente.

È anche molto più facile eseguire un test unitario di un componente in isolamento: invece di dargli un'implementazione effettiva dei componenti di cui ha bisogno, si usano semplicemente mock (possibilmente generati automaticamente).


Questa risposta riguarda l'inserimento delle dipendenze. So cos'è, so che è buono e lo dichiaro chiaramente nella prima frase della domanda. La domanda riguardava i vantaggi della configurazione DI, rispetto al semplice codice di inizializzazione.
Pavel Feldman,

Non risponde davvero alla domanda
Casebash
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.