JavaRush /Java Blog /Random-IT /Primavera. Lezione 2. IoC/DI nella pratica
Umaralikhon
Livello 3
Красноярск

Primavera. Lezione 2. IoC/DI nella pratica

Pubblicato nel gruppo Random-IT
E quindi... Nella lezione precedente abbiamo ripassato brevemente la parte teorica di IoC e DI. Impostiamo anche il file di configurazione pom.xml per il nostro progetto. Oggi iniziamo a creare la parte principale del programma. Innanzitutto, ti mostrerò come creare un programma senza IoC/DI. E poi creeremo direttamente un programma che introdurrà in modo indipendente le dipendenze. Cioè, il controllo del codice passa nelle mani del framework (sembra inquietante). Mentre gestiamo il programma, immagina che ci sia una certa azienda. E l'azienda (per ora) ha due dipartimenti: sviluppo Java e dipartimento assunzioni. Lascia che la classe che descrive il "Dipartimento di sviluppo Java" abbia due metodi: String getName() - che restituisce il nome del dipendente, String getJob() - che restituisce la posizione del dipendente. (Elenco 1)
package org.example;

public class JavaDevelopment {

    public String getName(){
        return "Alexa";
    }

    public String getJob(){
        return "Middle Java developer";
    }
}
Lascia che la classe che descrive il reparto assumente abbia un costruttore di input che accetta un dipendente e un metodo void displayInfo() che visualizza le informazioni sui dipendenti. (Elenco 2)
package org.example;

public class HiringDepartment {
    private JavaDevelopment javaDevelopment;

    public HiringDepartment(JavaDevelopment javaDevelopment) {
        this.javaDevelopment = javaDevelopment;
    }

    public void displayInfo() {
        System.out.println("Name: " + javaDevelopment.getName());
        System.out.println("Job: " + javaDevelopment.getJob());
    }
}
C'è anche Main, una classe che gestisce tutti i dipartimenti. (Elenco 3)
package org.example;

public class Main {
    public static void main(String ... args){
        JavaDevelopment javaDevelopment = new JavaDevelopment();
        HiringDepartment hiringDepartment = new HiringDepartment(javaDevelopment);

        hiringDepartment.displayInfo();
    }
}
Stabilità per ora. Quando eseguiamo la classe Main otteniamo il seguente risultato:
Name: Alexa
Job: Middle Java developer
Ora immaginiamo che l’azienda stia andando alla grande. Pertanto, hanno deciso di espandere la portata delle loro attività e hanno aperto un dipartimento di sviluppo Python. E qui sorge la domanda: come descrivere questo dipartimento a livello di programma? Risposta: devi “copiare e incollare” ovunque sia necessario descrivere questo reparto (il buon vecchio metodo🙃). Per prima cosa creiamo la classe stessa, che descriverebbe il dipartimento "Pythonisti". (Elenco 4)
package org.example;

public class PythonDevelopment {
    public String getName(){
        return "Mike";
    }

    public String getJob(){
        return "Middle Python developer";
    }
}
E poi lo trasferiremo al dipartimento assunzioni. E HiringDepartment non dice nulla su questo dipartimento. Dovrai quindi creare un nuovo oggetto della classe PythonDevelopment e un costruttore che accetti gli sviluppatori Python. Dovrai anche modificare il metodo displayInfo() in modo che visualizzi correttamente le informazioni. (Elenco 5)
package org.example;

public class HiringDepartment {
    private JavaDevelopment javaDevelopment;

    public HiringDepartment(JavaDevelopment javaDevelopment) {
        this.javaDevelopment = javaDevelopment;
    }


    //Тут создается отдел найма для Python - разработчиков
    private PythonDevelopment pythonDevelopment;

    public HiringDepartment(PythonDevelopment pythonDevelopment) {
        this.pythonDevelopment = pythonDevelopment;
    }

    //Тогда придется изменить метод displayInfo()
    public void displayInfo() {
        if(javaDevelopment != null) {
            System.out.println("Name: " + javaDevelopment.getName());
            System.out.println("Job: " + javaDevelopment.getJob());
        } else if (pythonDevelopment != null){
            System.out.println("Name: " + pythonDevelopment.getName());
            System.out.println("Job: " + pythonDevelopment.getJob());
        }
    }
}
Come possiamo vedere, il volume del codice è raddoppiato, o anche di più. Con una grande quantità di codice, la sua leggibilità diminuisce. E la cosa peggiore è che creiamo tutti gli oggetti manualmente e creiamo classi fortemente dipendenti l'una dall'altra. Ok, eravamo d'accordo con questo. Hanno appena descritto un dipartimento. Non perderemo nulla da questo. E se aggiungessimo un altro dipartimento? E se ce ne fossero due? Tre? Ma nessuno ha proibito “l’estrazione mineraria e il pascolo”. Primavera.  Lezione 2. IoC/DI in pratica - 1 Sì, nessuno ha proibito “Mine and Pasture”, ma non è professionale. Tyzh è un programmatore. E qui puoi usare DI. Cioè, lavoreremo non a livello di classe, ma a livello di interfaccia. Ora gli stati dei nostri oggetti verranno archiviati nelle interfacce. In questo modo, le dipendenze tra le classi saranno minime. Per fare ciò, creiamo prima l'interfaccia di sviluppo, che ha due metodi per descrivere un dipendente. (Elenco 6)
package org.example;

public interface Development {
    String getName();
    String getJob();
}
Lasciamo quindi che due classi JavaDevelopment e PythonDevelopment implementino (ereditino) da questa interfaccia e sovrascrivano i metodi String getName() e String getJob(). (Elenco 7, 8)
package org.example;

public class JavaDevelopment implements Development {
    @Override
    public String getName(){
        return "Alexa";
    }

    @Override
    public String getJob(){
        return "Middle Java developer";
    }
}
package org.example;

public class PythonDevelopment implements Development {
    @Override
    public String getName(){
        return "Mike";
    }

    @Override
    public String getJob(){
        return "Middle Python developer";
    }
}
Quindi nella classe HiringDepartment puoi semplicemente definire un oggetto interfaccia di tipo Development e puoi anche passare tale oggetto al costruttore. (Elenco 9)
package org.example;

public class HiringDepartment {
    private Development development; //Определяем интерфейс

    //Конструктор принимает an object интерфейса
    public HiringDepartment(Development development){
        this.development = development;
    }

    public void displayInfo(){
        System.out.println("Name: " + development.getName());
        System.out.println("Job: " + development.getJob());
    }
}
Come possiamo vedere, la quantità di codice è diminuita. E, cosa più importante, le dipendenze sono state ridotte al minimo. Come vengono effettivamente implementati i valori e le dipendenze per questi oggetti? Esistono tre modi per eseguire l'inserimento delle dipendenze:
  • Utilizzando il costruttore
  • Utilizzo dei setter
  • Autowiring (rilegatura automatica)
Implementazione utilizzando un costruttore Ora parliamo dell'implementazione utilizzando un costruttore. Guarda il Listato 9. Il costruttore della classe HiringDepartment si aspetta un oggetto di tipo Development come input. Cercheremo di iniettare dipendenze attraverso questo costruttore. Vale anche la pena notare che l'iniezione delle dipendenze viene eseguita utilizzando i cosiddetti contenitori Spring. Esistono tre modi per configurare i contenitori Spring:
  • Utilizzo di file XML (metodo obsoleto)
  • Utilizzo di annotazioni + file XML (modo moderno)
  • Utilizzo del codice Java (modo moderno)
Ora stiamo utilizzando la configurazione utilizzando file XML. Nonostante questo metodo sia considerato obsoleto, molti progetti vengono ancora scritti in questo modo. Pertanto è necessario sapere. Innanzitutto, devi creare un file xml nella cartella delle risorse. Puoi dargli qualsiasi nome, ma preferibilmente uno significativo. L'ho chiamato "applicationContext.xml". Primavera.  Lezione 2. IoC/DI in pratica - 2 In questo file scriveremo la seguente parte di codice (Listato 10):
<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="javaDeveloper" class="org.example.JavaDevelopment"/>
    <bean id="pythonDeveloper" class="org.example.PythonDevelopment"/>

    <bean id="hiringDepartment" class="org.example.HiringDepartment">
        <constructor-arg ref="javaDeveloper"/>
    </bean>

</beans>
Ora, in ordine. Le prime otto righe di codice non ci interessano, sono predefinite. Puoi semplicemente copiarli. Il tag <bean> </bean> definisce un bean Spring. Un bean è un oggetto creato e gestito da un contenitore Spring. In parole semplici, il contenitore Spring stesso crea per noi un nuovo oggetto di classe (ad esempio: JavaDevelopment javaDevelopment = new JavaDevelopment();). All'interno di questo tag ci sono gli attributi id e class. id specifica il nome del bean. Questo ID verrà utilizzato per accedere all'oggetto. È equivalente al nome di un oggetto in una classe Java. classe - definisce il nome della classe a cui è legato il nostro bean (oggetto). È necessario specificare il percorso completo della classe. Prestare attenzione al bean hiringDepartment. All'interno di questo bean c'è un altro tag <constructor-arg ref="javaDeveloper"/>. È qui che avviene l'iniezione delle dipendenze (nel nostro caso, l'iniezione utilizzando un costruttore). <constructor-arg> - indica a Spring che il contenitore Spring dovrebbe cercare le dipendenze nel costruttore della classe definito nell'attributo bean. E a quale oggetto deve essere associato è determinato dall'attributo ref , all'interno del tag <constructor-arg>. ref - indica l'id del bean da contattare. Se in ref al posto di javaDeveloper specifichiamo l'id pythonDeveloper, allora la connessione avviene con la classe PythonDevelopmen. Ora dobbiamo descrivere la classe Main. Apparirà così: (Listing11)
package org.example;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String ... args){
        //Определяем контекст файл в котором содержатся прописанные нами бины
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //Получем бины, которые были определены в файле applicationContext.xml
        HiringDepartment hiringDepartment = context.getBean("hiringDepartment", HiringDepartment.class);

        hiringDepartment.displayInfo();

        context.close(); //Контекст всегда должен закрываться
    }
}
Cosa c'è qui?
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Questa riga collega la classe Main al file .xml che descrive i nostri bean. Il valore passato al costruttore deve corrispondere al nome del file .xml. (Nel nostro caso applicationContext.xml).
HiringDepartment hiringDepartment = context.getBean("hiringDepartment", HiringDepartment.class);
Indica che vogliamo ottenere un bean (oggetto) della classe HiringDepartment. Il primo argomento punta all'id del bean che abbiamo scritto nel file xml. Il secondo argomento punta alla classe che vogliamo contattare. Questo processo è chiamato riflessione .
hiringDepartment.displayInfo();
 context.close(); //Контекст всегда должен закрываться
Qui otteniamo facilmente un metodo della classe HiringDepartment. Tieni presente che non abbiamo utilizzato la parola chiave new per ottenere gli oggetti e non abbiamo definito da nessuna parte oggetti dipendenti di tipo JavaDevelopment o PythonDevelopment. Sono stati semplicemente descritti nel file applicationContext.xml. Presta attenzione anche all'ultima riga. Dovresti sempre chiudere il contesto prima di spegnerlo. In caso contrario, le risorse non verranno liberate e potrebbe verificarsi una perdita di memoria o un funzionamento errato del programma. Se avete domande o suggerimenti scrivete nei commenti, risponderò sicuramente. Grazie per l'attenzione. Codice sorgente al link Il mio carrello GitHub Contenuto del corso Continua...
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION