Java Dependency Injection-DI Design Pattern Example Tutorial (Italiano)

Java Dependency Injection design pattern ci permette di rimuovere le dipendenze hard-coded e rendere la nostra applicazione liberamente accoppiato, estendibile e mantenibile. Possiamo implementare dependency injection in java per spostare la risoluzione delle dipendenze dal tempo di compilazione al runtime.,

Java Dependency Injection

Java Dependency injection sembra difficile da comprendere con la teoria, quindi vorrei fare un semplice esempio e poi vedremo come utilizzare il modello di iniezione delle dipendenze per ottenere accoppiamento libero ed estensibilità nell’applicazione.

Diciamo che abbiamo un’applicazione in cui consumiamo EmailService per inviare e-mail. Normalmente implementeremmo questo come di seguito.

EmailService classe contiene la logica per inviare un messaggio di posta elettronica all’indirizzo email del destinatario., Il nostro codice di applicazione sarà come di seguito.

Il nostro codice client che utilizzerà la classe MyApplication per inviare messaggi e-mail sarà come di seguito.

A prima vista, non sembra esserci nulla di sbagliato nell’implementazione di cui sopra. Ma sopra la logica del codice ha alcune limitazioni.

  • MyApplication la classe è responsabile di inizializzare il servizio di posta elettronica e quindi utilizzarlo. Questo porta alla dipendenza hard-coded. Se vogliamo passare a qualche altro servizio di posta elettronica avanzato in futuro, richiederà modifiche al codice nella classe MyApplication., Ciò rende la nostra applicazione difficile da estendere e se il servizio di posta elettronica viene utilizzato in più classi, sarebbe ancora più difficile.
  • Se vogliamo estendere la nostra applicazione per fornire una funzione di messaggistica aggiuntiva, come SMS o messaggi di Facebook, allora avremmo bisogno di scrivere un’altra applicazione per questo. Ciò comporterà modifiche al codice nelle classi di applicazioni e anche nelle classi client.
  • Testare l’applicazione sarà molto difficile poiché la nostra applicazione sta creando direttamente l’istanza del servizio di posta elettronica. Non c’è modo di prendere in giro questi oggetti nelle nostre classi di test.,

Si può sostenere che possiamo rimuovere la creazione dell’istanza del servizio di posta elettronica dalla classe MyApplication avendo un costruttore che richiede il servizio di posta elettronica come argomento.

Ma in questo caso, stiamo chiedendo alle applicazioni client o alle classi di test di inizializzare il servizio di posta elettronica che non è una buona decisione di progettazione.

Ora vediamo come possiamo applicare java dependency injection pattern per risolvere tutti i problemi con l’implementazione di cui sopra., L’iniezione di dipendenze in java richiede almeno quanto segue:

  1. I componenti del servizio devono essere progettati con classe di base o interfaccia. È meglio preferire interfacce o classi astratte che definiscano il contratto per i servizi.
  2. Le classi consumer dovrebbero essere scritte in termini di interfaccia di servizio.
  3. Classi iniettori che inizializzeranno i servizi e quindi le classi consumer.

Java Dependency Injection – Service Components

Per il nostro caso, possiamo avereMessageService che dichiarerà il contratto per le implementazioni del servizio.,

package com.journaldev.java.dependencyinjection.service;public interface MessageService {void sendMessage(String msg, String rec);}

Ora diciamo che abbiamo servizi di posta elettronica e SMS che implementano le interfacce di cui sopra.

I nostri servizi java dependency injection sono pronti e ora possiamo scrivere la nostra classe consumer.

Java Dependency Injection – Service Consumer

Non siamo tenuti ad avere interfacce di base per le classi consumer ma avrò un’interfacciaConsumer che dichiara il contratto per le classi consumer.

package com.journaldev.java.dependencyinjection.consumer;public interface Consumer {void processMessages(String msg, String rec);}

La mia implementazione della classe consumer è come di seguito.

Si noti che la nostra classe di applicazione sta solo utilizzando il servizio., Non inizializza il servizio che porta a una migliore “separazione delle preoccupazioni”. Anche l’uso dell’interfaccia di servizio ci consente di testare facilmente l’applicazione prendendo in giro MessageService e associare i servizi in fase di runtime piuttosto che in fase di compilazione.

Ora siamo pronti a scrivere classi java dependency injector che inizializzeranno il servizio e anche le classi consumer.

Java Dependency Injection – Classi di iniettori

Abbiamo un’interfacciaMessageServiceInjector con la dichiarazione del metodo che restituisce la classeConsumer.,

package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;public interface MessageServiceInjector {public Consumer getConsumer();}

Ora per ogni servizio, dovremo creare classi di iniettori come di seguito.

package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;import com.journaldev.java.dependencyinjection.consumer.MyDIApplication;import com.journaldev.java.dependencyinjection.service.EmailServiceImpl;public class EmailServiceInjector implements MessageServiceInjector {@Overridepublic Consumer getConsumer() {return new MyDIApplication(new EmailServiceImpl());}}

package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;import com.journaldev.java.dependencyinjection.consumer.MyDIApplication;import com.journaldev.java.dependencyinjection.service.SMSServiceImpl;public class SMSServiceInjector implements MessageServiceInjector {@Overridepublic Consumer getConsumer() {return new MyDIApplication(new SMSServiceImpl());}}

Ora vediamo come le nostre applicazioni client utilizzeranno l’applicazione con un semplice programma.

Come si può vedere che le nostre classi di applicazioni sono responsabili solo per l’utilizzo del servizio. Le classi di servizio vengono create negli iniettori. Inoltre, se dobbiamo estendere ulteriormente la nostra applicazione per consentire la messaggistica di Facebook, dovremo scrivere solo classi di servizi e classi di iniettori.,

Quindi l’implementazione di dependency injection ha risolto il problema con la dipendenza hard-coded e ci ha aiutato a rendere la nostra applicazione flessibile e facile da estendere. Ora vediamo quanto facilmente possiamo testare la nostra classe di applicazione prendendo in giro le classi di iniettore e servizio.

Java Dependency Injection – JUnit Test Case with Mock Injector and Service

Come puoi vedere, sto usando classi anonime per prendere in giro le classi injector e service e posso facilmente testare i miei metodi di applicazione., Sto usando JUnit 4 per la classe di test sopra, quindi assicurati che sia nel percorso di compilazione del progetto se stai eseguendo sopra la classe di test.

Abbiamo usato i costruttori per iniettare le dipendenze nelle classi di applicazione, un altro modo è usare un metodo setter per iniettare le dipendenze nelle classi di applicazione. Per l’iniezione di dipendenza del metodo setter, la nostra classe di applicazione verrà implementata come di seguito.

package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;import com.journaldev.java.dependencyinjection.consumer.MyDIApplication;import com.journaldev.java.dependencyinjection.service.EmailServiceImpl;public class EmailServiceInjector implements MessageServiceInjector {@Overridepublic Consumer getConsumer() {MyDIApplication app = new MyDIApplication();app.setService(new EmailServiceImpl());return app;}}

Uno dei migliori esempi di setter dependency injection è Struts2 Servlet API Aware interfaces.,

Se utilizzare l’iniezione di dipendenza basata sul costruttore o basata sul setter è una decisione di progettazione e dipende dalle tue esigenze. Ad esempio, se la mia applicazione non può funzionare affatto senza la classe del servizio, preferirei DI basato sul costruttore o altrimenti preferirei DI basato sul metodo setter per usarlo solo quando è veramente necessario.

L’iniezione di dipendenza in Java è un modo per ottenere l’inversione del controllo (IoC) nella nostra applicazione spostando gli oggetti che si legano dal tempo di compilazione al runtime., Possiamo raggiungere IoC attraverso il modello di fabbrica, il modello di progettazione del metodo del modello, il modello di strategia e il modello di localizzazione del servizio.

Spring Dependency Injection, Google Guice e Java EE CDI frameworks facilitano il processo di dependency injection attraverso l’uso di Java Reflection API e Java annotations. Tutto ciò di cui abbiamo bisogno è annotare il metodo field, constructor o setter e configurarli in file o classi xml di configurazione.,zione

Alcuni dei vantaggi dell’utilizzo di Dependency Injection in Java sono:

  • la Separazione delle Preoccupazioni
  • Codice Standard di riduzione in classi di applicazioni, perché tutto il lavoro per inizializzare le dipendenze è gestita dal iniettore componente
  • componenti Configurabili rende l’applicazione facilmente estensibile
  • Unit testing è facile con gli oggetti mock

Svantaggi di Java Dependency Injection

Java Dependency injection ha alcuni svantaggi troppo:

  • Se abusato, può portare a problemi di manutenzione, perché l’effetto di cambiamenti sono noti in fase di runtime.,
  • Dependency injection in java nasconde le dipendenze della classe di servizio che possono portare a errori di runtime che sarebbero stati rilevati in fase di compilazione.

Questo è tutto per il modello di iniezione delle dipendenze in java. È bene conoscerlo e usarlo quando abbiamo il controllo dei servizi.

Leave a Comment