Maison > Java > javaDidacticiel > le corps du texte

Principe d'inversion de dépendance

王林
Libérer: 2024-08-26 06:32:31
original
676 Les gens l'ont consulté

Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau. Les deux devraient dépendre d’abstractions.

Les abstractions ne devraient pas dépendre des détails, les détails devraient dépendre des abstractions.

Comprenons les Modules de haut niveau et les Modules de bas niveau à travers un exemple :

Dependency Inversion Principle

Dans une application de commerce électronique comme Flipkart, à un niveau élevé, elle peut être classée comme ProductCatalog, PaymentProcessor et CustomerProfile (ce sont quelques-unes des principales fonctions commerciales)
Ces fonctions métiers dépendent d'autres modules présentés dans l'image ci-dessus.

Remarque : les modules du dessus sont plus proches d'une fonction métier appelée modules de haut niveau.
Les modules en bas sont proches des détails d'implémentation appelés modules de Bas niveau.

Les modules de bas niveau sont SQLProductRepository, GooglePayService, WireTransfer, EmailSender et VoiceDialer.

Si nous considérons uniquement les modules CustomerProfile (module de haut niveau) et de communication, la communication est un module de bas niveau, mais si nous considérons uniquement la communication, EmailSender et VoiceDialer, la communication devient un module de haut niveau, et EmailSender et VoiceDialer sont des modules de bas niveau.

Le point ici, le concept de Module de niveau haut et bas n'est pas absolu mais relatif.

D'après l'image ci-dessus, ProductCatalog dépend de SQLProductRepository c'est-à-dire qu'un module de haut niveau dépend d'un module de bas niveau, mais cela directement entre en conflit avec la 1ère définition du DIP.


Prenons la relation ProductCatalog → SQLProductRepository et analysons-la plus en détail.

import java.util.List;
/*
 * High-Level module
*/
public class ProductCatalog {
    public void listAllProducts(){
        SQLProductRepository sqlProductRepository = new SQLProductRepository();
        List<String> allProductsNames = sqlProductRepository.getAllProductNames();
        //Display all products names
    }
}
Copier après la connexion
/*
 * Low-level module 
*/
import java.util.Arrays;
import java.util.List;
public class SQLProductRepository {
    public List<String> getAllProductNames(){
        return Arrays.asList("soap","toothpaste");
    }
}
Copier après la connexion

Comme ProductCatalog dépend directement de SQLProductRepository, il s'agit clairement d'une violation de la définition DIP 1 (selon la définition les modules de haut et de bas niveau doivent dépendre de l'abstraction)

Résolvons cela selon la définition 1 :

création de l'interface ProductRepository

import java.util.List;

public interface ProductRepository {
    public List<String> getAllProductNames();
}
Copier après la connexion

Implémentation de cette interface dans SQLProductRepository

/*
 * Low-level module 
*/
import java.util.Arrays;
import java.util.List;
public class SQLProductRepository  implements ProductRepository{
    @Override
    public List<String> getAllProductNames(){
        return Arrays.asList("soap","toothpaste");
    }
}
Copier après la connexion

Enfin, pour le module de haut niveau ProductCatalog, nous ne devrions pas y instancier directement SQLProductRepository. Nous utiliserons une classe ProductFactory pour la même chose

public class ProductFactory {
    public static ProductRepository create(){
        return new SQLProductRepository();
    }
}
Copier après la connexion

Nous utiliserons ProductFactory pour instancier le SQLProductRepository

/*
 * High-Level module
*/
import java.util.List;

public class ProductCatalog {
    public void listAllProducts(){
        ProductRepository productRepository = ProductFactory.create();
        List<String> allProductsNames = productRepository.getAllProductNames();
        //Display all products names
    }
}
Copier après la connexion

Notez que notre objet de référence est ProductRepository. Nous n'avons donc pas de couplage étroit avec SQLProductRepository

Après la modification, la nouvelle dépendance ressemblera à ceci

Dependency Inversion Principle

Les modifications ci-dessus sont conformes à la définition DIP 1.
Le changement de code ci-dessus suit également la 2ème définition de DIP, c'est-à-dire que l'abstraction ne devrait pas dépendre des détails, les détails devraient dépendre de l'abstraction.
Comme nous pouvons le voir dans l'image ci-dessus, SQLProductRepository dépend du ProductRepository et non l'inverse. C'est la raison pour laquelle ce principe est appelé principe d'inversion de dépendance


Injection de dépendances VS Inversion de dépendances

Even though they are related, they are not the same and can not be used interchangeably 
Copier après la connexion

Comprendre l'injection de dépendances :

Dans ProductCatalog, nous utilisons la méthode Factory ProductFactory.create() pour obtenir une instance de l'objet SQLProductRepository.
Bien qu'il délègue le processus de création d'instance à la classe d'usine ProductFactory, le processus d'initialisation relève toujours de la classe ProductCatalog.
Idéalement, nous ne voulons pas que la classe ProductCatelog se soucie de savoir comment et quand déclencher l'instanciation.
Et si nous fournissions la classe ProductRepository instanciée à ProductCatalog même sans qu'il nous le demande ?

Ainsi, la classe Main ECommerceMainApplication utilise la méthode d'usine ProductFactory.create() pour créer l'instance de ProductRepository et cette instance est passée en argument dans le constructeur de la classe ProductRepositroy.

public class ECommerceMainApplication {
    public static void main(String agrs[]) {
        ProductRepository productRepository = ProductFactory.create();
        ProductCatalog productCatalog = new ProductCatalog(productRepository);
        productCatalog.listAllProducts();
    }
}
Copier après la connexion

Après avoir mis à jour la classe ProductCatalog en conséquence

import java.util.List;

public class ProductCatalog {

    private ProductRepository productRepository;

    public ProductCatalog(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public void listAllProducts(){
        List<String> allProductsNames = productRepository.getAllProductNames();
        //Display all products names
        allProductsNames.forEach(product-> System.out.println(product));
    }
}
Copier après la connexion

Le ProductCatalog est désormais libre d'utiliser l'objet SQLProductRepository quand et où il le souhaite. Il n'a plus à se soucier de créer lui-même l'objet SQLProductRepository.
En d'autres termes nous injectons la dépendance dans le ProductCatalog au lieu que ProductCatalog se soucie de l'instanciation de la dépendance.
C'est le concept de injection de dépendances


Inversion de contrôle - IOC

Même s'il ne fait pas partie du DIP (Dependency Inversion Principe), il est étroitement lié

Comprenons cela avec le même code ci-dessus

La classe ProductCatalog avait un constructeur qui prenait l'objet ProductRepository.

La classe qui appelle le ProductCatalog fournira ou injectera l'objet de ProductRepository dans ce cas il s'agit de ECommerceMainApplication.
Notez que même si l'injection se produit en dehors de la classe ProductCatalog, l'injection se produit toujours pendant le flux principal du programme. c'est-à-dire que l'injection se produit dans le thread principal de l'exécution du programme.

Et si nous voulons que toutes les injections se produisent dans un thread séparé ou dans un contexte complètement séparé afin que le flux de contrôle principal soit complètement isolé de l'injection ?

Cela peut être réalisé en utilisant des frameworks comme Spring(en Java).

Dependency Inversion Principle

Spring exécutera son propre contexte différent du flux principal du programme
Spring se chargera d'injecter les dépendances requises d'une classe. Donc si vous souhaitez instancier l'objet d'une classe, au lieu de le faire vous-même directement dans le code, vous demandez à Spring de vous donner l'objet de la classe.
Le framework Spring examine toutes les dépendances requises pour l'instanciation de l'objet, puis va de l'avant et injecte toutes les dépendances, instancie l'objet et le restitue au flux de contrôle principal.
Ainsi, le contrôle de l'injection de dépendances est entièrement délégué au framework Spring et n'a pas lieu dans le flux de contrôle du courrier.
Ce concept est appelé Inversion de Contrôle (IOC) et le Printemps est appelé Inversion de Conteneur de Contrôle ou simplement un Conteneur IOC

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!