JavaRush /Blog Java /Random-FR /Printemps. Leçon 2. IoC/DI en pratique
Umaralikhon
Niveau 3
Красноярск

Printemps. Leçon 2. IoC/DI en pratique

Publié dans le groupe Random-FR
Et donc... Dans la leçon précédente, nous avons brièvement passé en revue la partie théorique de l'IoC et de la DI. Nous avons également configuré le fichier de configuration pom.xml pour notre projet. Aujourd'hui, nous commençons à créer la partie principale du programme. Tout d'abord, je vais vous montrer comment créer un programme sans IoC/DI. Et puis nous créerons directement un programme qui introduit indépendamment des dépendances. Autrement dit, le contrôle du code passe entre les mains du framework (cela semble effrayant). Pendant que nous gérons le programme, imaginez qu'il existe une certaine entreprise. Et l'entreprise dispose (pour l'instant) de deux départements : le département de développement Java et le département de recrutement. Laissez la classe décrivant le « Département de développement Java » avoir deux méthodes : String getName() - renvoyant le nom de l'employé, String getJob() - renvoyant le poste de l'employé. (Liste 1)
package org.example;

public class JavaDevelopment {

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

    public String getJob(){
        return "Middle Java developer";
    }
}
Laissez la classe décrivant le service d'embauche avoir un constructeur d'entrée qui accepte un employé et une méthode void displayInfo() qui affiche des informations sur les employés. (Liste 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());
    }
}
Il existe également Main - une classe qui gère tous les départements. (Liste 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é pour l'instant. Lorsque nous exécutons la classe Main, nous obtenons le résultat suivant :
Name: Alexa
Job: Middle Java developer
Imaginons maintenant que l’entreprise se porte très bien. Ils ont donc décidé d'élargir le champ de leurs activités et ont ouvert un département de développement Python. Et ici se pose la question : Comment décrire ce département au niveau du programme ? Réponse : il faut « copier-coller » partout où il faut décrire ce département (la bonne vieille méthode🙃). Tout d'abord, créons la classe elle-même, qui décrirait le département "Pythonistes". (Liste 4)
package org.example;

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

    public String getJob(){
        return "Middle Python developer";
    }
}
Et puis nous le transférerons au service du recrutement. Et HiringDepartment ne dit rien sur ce département. Par conséquent, vous devrez créer un nouvel objet de la classe PythonDevelopment et un constructeur acceptant les développeurs Python. Vous devrez également modifier la méthode displayInfo() pour qu'elle affiche correctement les informations. (Liste 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());
        }
    }
}
Comme on peut le constater, le volume de code a doublé, voire plus. Avec une grande quantité de code, sa lisibilité diminue. Et le pire, c'est que nous créons tous les objets manuellement et créons des classes fortement dépendantes les unes des autres. Ok, nous sommes d'accord avec ça. Ils viennent de décrire un ministère. Nous n’y perdrons rien. Eh bien, et si nous ajoutions un autre département ? Et s'il y en avait deux ? Trois? Mais personne n’a interdit « l’exploitation minière et le pâturage ». Printemps.  Leçon 2. IoC / DI en pratique - 1 Oui, personne n'a interdit « Mine and Pâturage », mais ce n'est pas professionnel. Tyzh est programmeur. Et ici, vous pouvez utiliser DI. Autrement dit, nous ne travaillerons pas au niveau de la classe, mais au niveau de l'interface. Désormais les états de nos objets seront stockés dans des interfaces. De cette façon, les dépendances entre les classes seront minimes. Pour ce faire, nous créons d’abord l’interface Développement, qui dispose de deux méthodes pour décrire un salarié. (Liste 6)
package org.example;

public interface Development {
    String getName();
    String getJob();
}
Laissez ensuite deux classes JavaDevelopment et PythonDevelopment implémenter (hériter) de cette interface et remplacer les méthodes String getName() et String getJob(). (Listes 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";
    }
}
Ensuite, dans la classe HiringDepartment, vous pouvez simplement définir un objet d'interface de type Development et vous pouvez également transmettre un tel objet au constructeur. (Liste 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());
    }
}
Comme nous pouvons le constater, la quantité de code a diminué. Et surtout, les dépendances ont été minimisées. Comment les valeurs et les dépendances sont-elles réellement implémentées pour ces objets ? Il existe trois façons de procéder à l'injection de dépendances :
  • Utiliser le constructeur
  • Utiliser des setters
  • Câblage automatique (reliure automatique)
Implémentation à l'aide d'un constructeur Parlons maintenant de l'implémentation à l'aide d'un constructeur. Regardez le listing 9. Le constructeur de la classe HiringDepartment attend un objet de type Development en entrée. Nous allons essayer d'injecter des dépendances via ce constructeur. Il convient également de noter que l'injection de dépendances est effectuée à l'aide des conteneurs Spring. Il existe trois façons de configurer les conteneurs Spring :
  • Utilisation de fichiers XML (méthode obsolète)
  • Utilisation d'annotations + fichiers XML (manière moderne)
  • Utiliser du code Java (méthode moderne)
Nous utilisons maintenant la configuration à l'aide de fichiers XML. Malgré le fait que cette méthode soit considérée comme obsolète, de nombreux projets sont encore rédigés de cette manière. Il faut donc le savoir. Tout d'abord, vous devez créer un fichier XML dans le dossier des ressources. Vous pouvez lui donner n’importe quel nom, mais de préférence un nom significatif. Je l'ai appelé "applicationContext.xml". Printemps.  Leçon 2. IoC / DI en pratique - 2 Dans ce fichier, nous écrirons le morceau de code suivant (Listing 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>
Maintenant, dans l'ordre. Les huit premières lignes de code ne nous intéressent pas, elles sont par défaut. Vous pouvez simplement les copier. La balise <bean> </bean> définit un bean Spring. Un bean est un objet créé et géré par un conteneur Spring. En termes simples, le conteneur Spring lui-même crée un nouvel objet de classe pour nous (par exemple : JavaDevelopment javaDevelopment = new JavaDevelopment();). À l’intérieur de cette balise se trouvent les attributs id et class. id spécifie le nom du bean. Cet identifiant sera utilisé pour accéder à l'objet. C'est l'équivalent du nom d'un objet dans une classe Java. class - définit le nom de la classe à laquelle notre bean (objet) est lié. Vous devez spécifier le chemin complet de la classe. Faites attention au bean HiringDepartment. À l'intérieur de ce bean, il y a une autre balise <constructor-arg ref="javaDeveloper"/>. C'est là que se produit l'injection de dépendances (dans notre cas, l'injection à l'aide d'un constructeur). <constructor-arg> - indique à Spring que le conteneur Spring doit rechercher les dépendances dans le constructeur de classe défini dans l'attribut du bean. Et l'objet auquel il faut associer est déterminé par l' attribut ref , à l'intérieur de la balise <constructor-arg>. ref - indique l'identifiant du bean à contacter. Si dans ref au lieu de javaDeveloper nous spécifions l'identifiant pythonDeveloper, alors la connexion se produit avec la classe PythonDevelopmen. Nous devons maintenant décrire la classe Main. Cela ressemblera à ceci : (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(); //Контекст всегда должен закрываться
    }
}
Qu'est ce qu'il y a ici?
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Cette ligne relie la classe Main au fichier .xml qui décrit nos beans. La valeur transmise au constructeur doit correspondre au nom du fichier .xml. (Dans notre cas applicationContext.xml).
HiringDepartment hiringDepartment = context.getBean("hiringDepartment", HiringDepartment.class);
Indique que nous voulons obtenir un bean (objet) de la classe HiringDepartment. Le premier argument pointe vers l'identifiant du bean que nous avons écrit dans le fichier XML. Le deuxième argument pointe vers la classe que nous souhaitons contacter. Ce processus s'appelle la réflexion .
hiringDepartment.displayInfo();
 context.close(); //Контекст всегда должен закрываться
Ici, nous obtenons facilement une méthode de la classe HiringDepartment. Notez que nous n’avons pas utilisé le mot-clé new pour obtenir les objets et que nous n’avons défini nulle part d’objets dépendants de type JavaDevelopment ou PythonDevelopment. Ils ont été simplement décrits dans le fichier applicationContext.xml. Faites également attention à la dernière ligne. Vous devez toujours fermer le contexte avant de l'arrêter. Sinon, les ressources ne seront pas libérées et une fuite de mémoire ou un fonctionnement incorrect du programme pourrait se produire. Si vous avez des questions ou des suggestions, écrivez dans les commentaires, je répondrai certainement. Merci de votre attention. Code source sur le lien Mon panier GitHub Contenu du cours À suivre...
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION