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 :
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 } }
/* * Low-level module */ import java.util.Arrays; import java.util.List; public class SQLProductRepository { public List<String> getAllProductNames(){ return Arrays.asList("soap","toothpaste"); } }
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(); }
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"); } }
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(); } }
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 } }
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
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
Even though they are related, they are not the same and can not be used interchangeably
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(); } }
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)); } }
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
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).
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!