Heim >Java >javaLernprogramm >Abhängigkeitsinversionsprinzip
High-Level-Module sollten nicht von Low-Level-Modulen abhängen. Beide sollten von Abstraktionen abhängen.
Abstraktionen sollten nicht von Details abhängen, Details sollten von Abstraktionen abhängen.
Lassen Sie uns die High-Level-Module und Low-Level-Module anhand eines Beispiels verstehen:
In einer E-Commerce-App wie Flipkart auf hoher Ebene kann sie in Produktkatalog, Zahlungsprozessor und Kundenprofil kategorisiert werden (dies sind einige der wichtigsten Geschäftsfunktionen)
Diese Geschäftsfunktionen hängen von anderen Modulen ab, die im obigen Bild gezeigt werden.
Hinweis: Die Module oben ähneln eher einer Geschäftsfunktion, die als High-Level-Module bezeichnet wird.
Die Module unten befinden sich in der Nähe der Implementierungsdetails, die als Low--Module bezeichnet werden.
Low-Level-Module sind SQLProductRepository, GooglePayService, WireTransfer, EmailSender und VoiceDialer.
Wenn wir nur die Module „CustomerProfile“ (High-Level-Modul) und „Communication“ betrachten, ist „Communication“ ein Low-Level-Modul. Wenn wir jedoch „Communication“, „EmailSender“ und „VoiceDialer“ allein betrachten, wird „Communication“ zu einem High-Level-Modul und „EmailSender“ usw VoiceDialer sind Low-Level-Module.
Der Punkt hier ist, dass das Konzept des High- und Low-Level-Moduls nicht absolut, sondern relativ ist.
Gemäß dem Bild oben hängt ProductCatalog von SQLProductRepository ab, d. h. ein High-Level-Modul hängt von einem Low-Level-Modul ab, aber dies steht direkt im Widerspruch zur ersten Definition des DIP
.
Nehmen wir die Beziehung ProductCatalog → SQLProductRepository und analysieren sie weiter.
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"); } }
Da ProductCatalog direkt von SQLProductRepository abhängt, stellt dies eindeutig einen Verstoß gegen DIP-Definition 1 dar (gemäß der Definition sollten sowohl High- als auch Low-Level-Module von der Abstraktion abhängen
)Beheben wir das Problem gemäß Definition 1:
Schnittstelle ProductRepository erstellen
import java.util.List; public interface ProductRepository { public List<String> getAllProductNames(); }
Implementierung dieser Schnittstelle in 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"); } }
Schließlich sollten wir für das High-Level-Modul ProductCatalog SQLProductRepository nicht
direkt darin instanziieren. Wir werden dafür eine ProductFactory-Klasse verwenden
public class ProductFactory { public static ProductRepository create(){ return new SQLProductRepository(); } }
Wir werden ProductFactory verwenden, um das SQLProductRepository zu instanziieren
/* * 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 } }
Beachten Sie, dass unser Referenzobjekt ProductRepository ist. Wir haben also keine enge Kopplung mit SQLProductRepository
Nach der Änderung sieht die neue Abhängigkeit in etwa so aus
Die oben genannten Änderungen entsprechen der DIP-Definition 1.
Die obige Codeänderung folgt auch der 2. Definition von DIP, d. h. Abstraktion sollte nicht von den Details abhängen, Details sollten von der Abstraktion abhängen.
Wie wir im Bild oben sehen können, hängt SQLProductRepository vom ProductRepository ab und nicht umgekehrt. Aus diesem Grund wird dieses Prinzip als Abhängigkeitsinversionsprinzip bezeichnet
Even though they are related, they are not the same and can not be used interchangeably
Abhängigkeitsinjektion verstehen:
In ProductCatalog verwenden wir die Factory-Methode ProductFactory.create(), um eine Instanz des SQLProductRepository-Objekts abzurufen.
Obwohl der Instanzerstellungsprozess an die Factory-Klasse ProductFactory delegiert wird, erfolgt der Initialisierungsprozess immer noch bei der ProductCatalog-Klasse.
Im Idealfall möchten wir nicht, dass sich die ProductCatelog-Klasse Gedanken darüber macht, wie und wann die Instanziierung ausgelöst wird.
Die Hauptklasse ECommerceMainApplication nutzt also die Factory-Methode ProductFactory.create(), um die Instanz von ProductRepository zu erstellen, und diese Instanz wird als Argument im Konstruktor der ProductRepositroy-Klasse übergeben.
public class ECommerceMainApplication { public static void main(String agrs[]) { ProductRepository productRepository = ProductFactory.create(); ProductCatalog productCatalog = new ProductCatalog(productRepository); productCatalog.listAllProducts(); } }
Nachdem die ProductCatalog-Klasse entsprechend aktualisiert wurde
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)); } }
Jetzt kann ProductCatalog das SQLProductRepository-Objekt jederzeit und überall verwenden. Es muss sich nicht mehr darum kümmern, das SQLProductRepository-Objekt selbst zu erstellen.
Mit anderen Worten wir injizieren die Abhängigkeit
in den ProductCatalog, anstatt dass sich ProductCatalog um die Instanziierung der Abhängigkeit kümmert.
Dies ist das Konzept der Abhängigkeitsinjektion
Obwohl es nicht Teil von DIP (Dependency Inversion Principle) ist, ist es eng damit verbunden
Lassen Sie uns dies mit dem gleichen obigen Code verstehen
Die Klasse ProductCatalog hatte einen Konstruktor, der das ProductRepository-Objekt aufnahm.
Die Klasse, die ProductCatalog aufruft, stellt das Objekt von ProductRepository bereit oder injiziert es in diesem Fall ECommerceMainApplication.
Beachten Sie, dass die Injektion dennoch während des Hauptablaufs des Programms erfolgt, auch wenn die Injektion außerhalb der ProductCatalog-Klasse erfolgt. d. h. die Injektion erfolgt im Hauptthread der Programmausführung.
Was wäre, wenn wir möchten, dass alle Injektionen in einem separaten Thread oder in einem separaten Kontext erfolgen, sodass der Hauptkontrollfluss vollständig von der Injektion isoliert ist?
Dies kann mit Frameworks wie Spring(in Java) erreicht werden.
Spring führt seinen eigenen Kontext aus, der sich vom Hauptablauf des Programms unterscheidet
Spring kümmert sich darum, die erforderlichen Abhängigkeiten einer Klasse einzufügen. Wenn Sie also das Objekt einer Klasse instanziieren möchten, bitten Sie Spring, Ihnen das Objekt der Klasse zu geben, anstatt es selbst direkt im Code zu tun.
Das Spring-Framework prüft alle für die Instanziierung des Objekts erforderlichen Abhängigkeiten, fügt dann alle Abhängigkeiten ein, instanziiert das Objekt und gibt es an den Hauptkontrollfluss zurück.
Somit wird die Kontrolle über die Abhängigkeitsinjektion vollständig an das Spring-Framework delegiert und findet nicht im Mail-Kontrollfluss statt.
Dieses Konzept wird Inversion of Control (IOC) genannt und die Feder wird Inversion of Control Container oder einfach ein IOC-Container
Das obige ist der detaillierte Inhalt vonAbhängigkeitsinversionsprinzip. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!