In letzter Zeit war ich immer Programmierprinzipien oder Mustern wie IOC (Inversion of Control), DI (Abhängigkeitsinjektion) ausgesetzt, und dies ist der Kern der berühmten Java -Frameworks Spring, Streben usw. Als Antwort darauf habe ich verschiedene Elemente in Wikipedia überprüft und relevante Bücher aus der Bibliothek ausgeliehen. Nachdem ich sie gelesen habe, habe ich etwas Verständnis. Jetzt werde ich die Erklärungen im Buch und meine eigene Verarbeitung kombinieren und sie wie folgt aussortieren:
EG1
Problembeschreibung:
Entwickeln Sie ein System, das Berichte im Excel- oder PDF -Format entsprechend unterschiedlichen Anforderungen erstellen kann, z. B. tägliche Berichte, monatliche Berichte usw.
Lösung:
Gemäß dem Prinzip der "interface-orientierten Programmierung" sollte die Schnittstelle und Implementierung getrennt werden, dh die Funktion der Erzeugung von Berichten wird in einen allgemeinen Schnittstellenberichtsgenerator extrahiert, und zwei Implementierungen, die Excel- und PDF-Berichte in Excel- und PDF-Formaten generieren. Der Client erhält dann die entsprechende Berichtsdruckfunktion über den Dienstanbieter ReportService.
Implementierungsmethode:
Nach dem obigen Angaben wird das folgende Klassendiagramm erhalten:
Code -Implementierung:
Schnittstelle ReportGenerator {public void generate (Tabelle Tabelle); } class excelGenerator implementiert reportGenerator {public void generate (Tabelle Tabelle) {System.out.println ("Ein Excel -Bericht generieren ..."); }} class pdfgenerator implementiert reportGenerator {public void generate (Tabelle Tabelle) {System.out.println ("Ein PDF -Bericht generieren ..."); }} class ReportService {// verantwortlich für die Erstellung des Berichtsgenerators für bestimmte Bedürfnisse private ReportGenerator Generator = new pdfGenerator (); // private statische ReportGenerator Generator = new ExcelGenerator (); public void getDailyReport (Datum Datum) {table.setDate (Datum); // ... Generator.Generate (Tabelle); } public void GetMonthlyReport (Monat Monat) {Table.SetMonth (Monat); // ... Generator.Generate (Tabelle); }} public class Client {public static void main (String [] args) {ReportService ReportService = new ReportService (); ReportService.getDailyReport (neues Datum ()); //reportService.getMonthLyReport(New Date ()); }}
EG2
Problembeschreibung:
Wie in den Kommentaren im obigen Code gezeigt, wird der spezifische Berichtsgenerator in der Berichtsdauer-Klasse von hart codiert erstellt, sodass ReportService direkt auf PDFGenerator oder ExcelGenerator gestützt wurde und diese offensichtliche enge Kopplung beseitigt werden muss.
Lösung: Führen Sie Container ein, um einen Zwischenmanager einzuführen, dh den Container (Container), der die am Berichtssystem beteiligten Objekte einheitlich verwaltet (hier eine Komponente, wir nennen es eine Bohne), einschließlich ReportService und verschiedenen XXGeneratoren. Hier verwenden Sie eine Hashmap-Instanz in Form eines Schlüsselwertpaars, um diese Bohnen zu retten.
Implementierungsmethode:
Das Klassendiagramm wird wie folgt erhalten:
Code -Implementierung:
Klassencontainer {// verschiedene erforderliche Komponenten in Schlüsselwertpaaren SABE SPAND STATIC MAP <string, Objekt> Beans; public container () {beans = new HashMap <String, Object> (); // spezifische Berichtsgenerator ReportGenerator ReportGenerator erstellen und speichern. Beans.put ("ReportGenerator", ReportGenerator); // Die Referenz von ReportService -ReportService -ReportService = new ReportService () erhalten und verwalten; Beans.put ("ReportService", ReportService); } public statisches Objekt getBean (String -ID) {return beans.get (id); }} Klasse ReportService {// eliminieren Sie die enge Kopplungsbeziehung und ersetzen Sie sie durch den Container // private statische ReportGenerator Generator = new pdfGenerator (); private ReportGenerator Generator Generator = (ReportGenerator) Container.getBean ("ReportGenerator"); public void getDailyReport (Datum Datum) {table.setDate (Datum); Generator.generate (Tabelle); } public void GetMonthlyReport (Monat Monat) {Table.SetMonth (Monat); Generator.generate (Tabelle); }} public class Client {public static void main (String [] args) {Container container = new Container (); ReportService ReportService = (ReportService) Container.getBean ("ReportService"); ReportService.getDailyReport (neues Datum ()); //reportService.getMonthLyReport(New Date ()); }}
Das Timing -Diagramm ist ungefähr wie folgt:
Wirkung:
Wie oben gezeigt, ist ReportService nicht mehr direkt mit dem spezifischen ReportGenerator verbunden. Es hat Container verwendet, um die Schnittstelle und Implementierung zu isolieren und die Wiederverwendbarkeit von Systemkomponentenbohnen zu verbessern. Zu diesem Zeitpunkt können Sie auch Konfigurationsdateien verwenden, um die Definition bestimmter Komponenten im Container in Echtzeit zu erhalten.
EG3
Problembeschreibung:
Wenn Sie sich jedoch das obige Klassendiagramm ansehen, ist es leicht festzustellen, dass es eine Zwei-Wege-Beziehung zwischen ReportService und Container gibt und gegenseitige Abhängigkeiten haben. Wenn Sie ReportService wiederverwenden möchten, hängt dies auch direkt von der spezifischen Suchlogik eines einzelnen Containers ab. Wenn andere Container unterschiedliche Komponenten -Suchmechanismen (z. B. JNDI) aufweisen, bedeutet die Wiederverwendung von ReportService zu diesem Zeitpunkt, dass die interne Suchlogik des Containers geändert werden muss.
Lösung: Einführung des Service Locator
Das erneute Einbau eines indirekten Layer-Service-Locators wird verwendet, um eine Schnittstelle für die Komponentensuchlogik bereitzustellen. Bitte beachten Sie die Beschreibung in Wikipedia oder die Beschreibung von Java ee 1 und 2.. Dies ermöglicht die mögliche Isolierung möglicher Änderungen.
Implementierungsmethode:
Das Klassendiagramm lautet wie folgt:
Code -Implementierung:
// In der tatsächlichen Anwendung können Sie die Schnittstelle verwenden, um einen einheitlichen Schnittstellenklassen -Servicelocator {private statische Container Container = New Container () anzugeben. public static reportGenerator getReportGenerator () {return (ReportGenerator) Container.getbean ("ReportGeneraator"); }} class ReportService {private reportGenerator reportGenerator = servicelocator.getReportGenerator (); // ...}EG4
Problembeschreibung:
Unabhängig davon, ob es jedoch einen Container einführt oder den Service -Locator verwendet, ist ReportService bei der Suche und Erstellung spezifischer Komponenten "aktiv", was bedeutet, dass der ReportService als Kunde klar sein muss, was er benötigt, wo es erhalten werden kann und wie er erhalten werden kann. Plötzlich müssen spezifische logische Details aufgrund was, wo und wie hinzugefügt werden.
Beispielsweise gibt es in der vorherigen Implementierungsmethode "Container einführen" der folgende Code:
Klasse ReportService {// eliminieren Sie die enge Kopplungsbeziehung und ersetzen Sie sie durch den Container // privaten statischen ReportGenerator Generator = new pdfGenerator (); // Private ReportGenerator Generator = (ReportGenerator) Container .getBean ("ReportGenerator");
In der Implementierungsmethode "Einführung des Dienstlocators" gibt es den folgenden Code:
Klasse Servicelocator {privatestatischer Container Container = neuer Container (); publicStatic reportGenerator getReportGenerator () {// Es ist immer noch Container.getbean (), nur ein Delegierter wird verwendet (ReportGenerator) Container.getbean ("ReportGeneraator"); }} class ReportService {// ReportService am Ende, es ist immer noch "aktiv" gesucht und delegiert an servicelocator private reportGenerator reportGenerator = servicelocator.getReportGenerator (); }
Lösung:
In diesem Fall wird das Ändern von „aktivem“ in „passiv“ zweifellos das interne Wissen über ReportService (d. H. Die Logik des Finden von Komponenten) verringern. Nach dem Prinzip der Kontrollinversion (IOC) wird dieser Zug (Zug, aktiv) in einen Push -Modus (Push, Passive) umgewandelt.
Das von uns normalerweise verwendete RSS -Abonnement ist beispielsweise eine Push -Anwendung, die uns den Ärger erspart, sich mehrmals am Tag auf unserer bevorzugten Website zu protokollieren, um aktiv Artikelaktualisierungen zu erhalten.
Die Abhängigkeitsinjektion (DI) erreicht diese Art von passivem Empfang und reduziert die Probleme der Kunden (hier, ReportService), die eine komplexe Logik enthalten und zu viel wissen.
Implementierungsmethode:
Da wir eine "passive" Empfang sein wollen, sollten wir zum Containerbeispiel zurückkehren, ohne den Service Locator -Modus zu verwenden. Das modifizierte Klassendiagramm wird daraus wie folgt erhalten:
Das ursprüngliche Klassendiagramm lautet wie folgt. Sie können es überprüfen und auf die Kommentaraufforderungen achten:
Code -Implementierung:
Um das Beispiel zu ermöglichen, und die laufenden Ergebnisse des Tracking -Codes zu verwenden, um das gesamte Klassendiagramm explizit zu instanziieren und miteinander zusammenzuarbeiten, wurden viele nummerierte Druckaussagen und zwei unbedeutende Klassen zu dem Konstruktor jeder Klasse hinzugefügt, die wie folgt ein wenig ertragbar ist: wie folgt:
Import Java.util.date; Import Java.util.hashMap; Import Java.util.Map; // Um kompilieren und laufen zu können, gibt es zwei weitere unbedeutende Klassen. Klassenmonat {} Klasse Tabelle {publicVoid setDate (Datum Datum) {} publicVoid setMonth (Monat Monat) {}} // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- von ExcelGenerator ... "); } publicVoid generate (Tabelle Tabelle) {System.out.println ("Ein Excel -Bericht generieren ..."); }} class pdfgenerator implementiert reportGenerator {public pdfGenerator () {System.out.println ("2 ... Initialisierung von PDFGenerator starten ..."); } publicVoid generate (Tabelle Tabelle) {System.out.println ("Ein PDF -Bericht generieren ..."); }} // ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Erhalten und verwalten Sie die Referenz von ReportService ReportService ReportService = New ReportService (); // die spezifische ReportGenerator -Instanz injizieren, die oben erstellt wurde. Beans.put ("ReportService", ReportService); System.out.println ("5 ... Endinitialisierungsbehälter ..."); } publicStatic Object getBean (String -ID) {System.out.println ("zuletzt Get Service Component ... getBean () ->" + id + "..."); returnBeans.get (id); }} class ReportService {// private statische ReportGenerator Generator = new pdfGenerator (); // Die enge Kupplungsbeziehung oben beseitigen und durch den Container ersetzen // private reportGenerator Generator = (ReportGenerator) Container // .getbean ("ReportGenerator"); // Entfernen Sie die oben genannte "aktive" Suche und geben Sie private Felder an, um das extern injizierte Objekt Private ReportGenerator -Generator zu speichern. // PublicVoid von außen im Setter Formular SetReportGenerator (ReportGenerator Generator) {System.out.println ("4 ... Start Inject ReportGenerator ..."); this.generator = Generator; } private table table = new table (); public ReportService () {System.out.println ("3 ... Start Initialization ReportService ..."); } publicVoid getDailyReport (Datum Datum) {table.setDate (Datum); Generator.generate (Tabelle); } publicVoid GetMonthlyReport (Monat Monat) {table.SetMonth (Monat); Generator.generate (Tabelle); }} publicClass Client {publicStaticVoid main (String [] args) {// Initialisieren Sie den neuen Container (); ReportService ReportService = (ReportService) Container .getBean ("ReportService"); ReportService.getDailyReport (neues Datum ()); // ReportService.getMonthLyReport (New Date ()); }}
Auslaufergebnisse:
1 ... Initialisierungsbehälter starten ... 2 ... Start Initialisierung
Beachten:
1. Gemäß der Druckreihenfolge der obigen Laufergebnisse ist ersichtlich, dass die dem Code hinzugefügte spezifische Zahl angemessen ist, was den Prozess der Programmausführung simuliert und so keine Sequenzdiagramme mehr zeichnet.
2. Beachten Sie, dass die Verwendung von IOC und DI in diesem Beispiel auf ReportService als Client (d. H. Komponente Demander) basiert, und der Testcode in der Client -Klasse Main () im Code ist der Endbenutzer der Servicekomponente, aber was sie benötigt, ist nicht die Komponente, sondern die Dienste, die die Komponente hat.
3. In der Tat ist in der Springbox -Clip den Container offensichtlich nicht das, was der Endbenutzerclient tun sollte, sondern im Voraus vom Dienstanbieter gestartet werden sollte.
V. In bestimmten Anwendungen werden die verfügbaren Servicekomponenten normalerweise mit XML und anderen Konfigurationsdateien auf dem Server bereitgestellt. Anschließend werden die Konfigurationsdateien vom Container gelesen und mit Reflexionstechnologie kombiniert, um bestimmte Servicekomponenten zu erstellen und zu injizieren.
analysieren:
Zuvor forderte der ReportService die Servicekomponente aktiv aus dem Container an, wartete jedoch passiv auf die Containerinjektion (Inject, dh Push) -Dienstkomponente. Die Steuerung wird offensichtlich aus dem zugrunde liegenden Modul (ReportService ist der Komponenten-Demander) auf das hochrangige Modul (Container ist der Komponentenanbieter) übertragen, dh die Kontrolle wird umgekehrt.