Récemment, j'ai toujours été exposé à des principes de programmation ou à des modèles tels que le CIO (inversion du contrôle), DI (injection de dépendance), et ceux-ci sont au cœur des célèbres frameworks Java, des entretoises, des entretoises, etc. En réponse à cela, j'ai vérifié divers éléments dans Wikipedia et emprunté des livres pertinents du libraire. Après les avoir lus, j'ai une certaine compréhension. Maintenant, je vais combiner les explications du livre et mon propre traitement et les régler comme suit:
EG1
Description du problème:
Développer un système qui peut générer des rapports au format Excel ou PDF selon différentes exigences, telles que les rapports quotidiens, les rapports mensuels, etc.
Solution:
Selon le principe de la "programmation orientée vers l'interface", l'interface et l'implémentation doivent être séparées, c'est-à-dire que la fonction de génération de rapports est extraite dans un rapport de rapport d'interface général, et deux implémentations qui génèrent des rapports Excel et PDF dans des formats Excel et PDF sont fournis. Le client obtient ensuite la fonction d'impression du rapport correspondant via le fournisseur de services ReportService.
Méthode d'implémentation:
Selon ce qui précède, le diagramme de classe suivant est obtenu:
Implémentation du code:
Interface ReportGenerator {public void generate (table table); } class ExcelGenerator implémente ReportGenerator {public void generate (Table Table) {System.out.println ("générer un rapport Excel ..."); }} classe PDFGenerator implémente ReportGenerator {public void generate (Table Table) {System.out.println ("Générer un rapport PDF ..."); }} classe RAPPORTSERVICE {// responsable de la création du générateur de rapports pour des besoins spécifiques privé Generator Generator = new PdfGenerator (); // Générateur de relevés de rapport statique privé = new ExcelGenerator (); public void getDailyReport (date de date) {table.setDate (date); // ... Generator.Generate (Table); } public void getMonthlyReport (mois mois) {table.setMonth (mois); // ... Generator.Generate (Table); }} public class Client {public static void main (String [] args) {reportService reportService = new Reportservice (); reportService.getDailyReport (new Date ()); //ReportService.getMonthlyreport(NEW DATE ()); }}
EG2
Description du problème:
Comme indiqué dans les commentaires dans le code ci-dessus, le générateur de rapports spécifique est créé par le code dur en interne dans la classe ReportsEservice, de sorte que ReportService s'est appuyé directement sur PDFGenerator ou ExcelGenerator, et cet couplage serré évident doit être éliminé.
Solution: introduire les conteneurs pour introduire un gestionnaire intermédiaire, c'est-à-dire le conteneur (conteneur), qui gère uniformément les objets impliqués dans le système de rapports (voici un composant, nous l'appelons un bean), y compris le service de reportage et divers xxgenerrateurs. Ici, vous utilisez une instance HashMap sous la forme d'une paire de valeurs clés pour enregistrer ces haricots.
Méthode d'implémentation:
Le diagramme de classe est obtenu comme suit:
Implémentation du code:
CLASS CONTAISER {// Enregistrer divers composants requis dans les paires de valeurs clés du bean mappe statique privée <String, objet> Beans; public conteneur () {beans = new hashmap <string, objet> (); // Créer et enregistrer le générateur de rapports spécifique rapport ReportGenerator ReportGenerator = new PdfGenerator (); Beans.put ("ReportGenerator", ReportGenerator); // Obtenez et gérez la référence de ReportsService RapportService Reportservice = new Reportservice (); Beans.put ("ReportsService", ReportService); } objet statique public getBean (String id) {return beans.get (id); }} classe reportService {// Éliminez la relation de couplage serrée et remplacez-la par le conteneur // Générateur de rapport de rapport statique privé = new pdfGenerator (); GÉNÉRATEUR DE GÉNÉRATEUR PRIVÉ RAPPORTAGE = (ReportGenerator) Container.getBean ("ReportGenerator"); public void getDailyReport (date de date) {table.setDate (date); générateur. Genèdre (tableau); } public void getMonthlyReport (mois mois) {table.setMonth (mois); générateur. Genèdre (tableau); }} public class Client {public static void main (String [] args) {contener Container = new Container (); RAPPORTSERVICE RAPPORTSERVICE = (RAPPORTSERVICE) Container.getBean ("RAPPORTSERVICE"); reportService.getDailyReport (new Date ()); //ReportService.getMonthlyreport(NEW DATE ()); }}
Le tableau de synchronisation est à peu près le suivant:
Effet:
Comme indiqué ci-dessus, ReportsService n'est plus directement associé au rapport spécifique. Il a utilisé des conteneurs pour isoler l'interface et la mise en œuvre, améliorant la réutilisabilité des haricots du composant système. À l'heure actuelle, vous pouvez également utiliser des fichiers de configuration pour obtenir la définition de composants spécifiques dans le conteneur en temps réel.
EG3
Description du problème:
Cependant, si vous regardez le diagramme de classe ci-dessus, il est facile de constater qu'il existe une relation bidirectionnelle entre ReportService et Container, et ils ont des dépendances mutuelles. Et, si vous souhaitez réutiliser ReportService, cela dépend également directement de la logique de recherche spécifique d'un seul conteneur. Si d'autres conteneurs ont des mécanismes de recherche de composants différents (tels que JNDI), la réutilisation de ReportsService pour le moment signifie que la logique de recherche interne du conteneur doit être modifiée.
Solution: Présentation du localisateur de service
La réintroduction d'un localisateur de service de couche indirect est utilisée pour fournir une interface pour la logique de recherche de composants. Veuillez consulter la description dans Wikipedia ou la description de celui-ci par Java EE 1 et 2. Cela permettra l'isolement possible des changements possibles.
Méthode d'implémentation:
Le diagramme de classe est le suivant:
Implémentation du code:
// Dans l'application réelle, vous pouvez utiliser l'interface pour fournir une classe d'interface unifiée Servicelocator {Private Static Container Container = new Container (); public static ReportGenerator getReportGenerator () {return (reportGenerator) contener.getBean ("reportGenerator"); }} classe reportService {private reportGenerator reportGenerator = ServiceLocator.getReportGenerator (); // ...}EG4
Description du problème:
Cependant, qu'il s'agisse d'introduire un conteneur ou d'utiliser un localisateur de service, RapportService est `` actif '' dans la recherche et la création de composants spécifiques, ce qui signifie qu'en tant que client, le service de reportage doit être clair sur ce dont il a besoin, où il peut être obtenu et comment il peut être obtenu. Tout d'un coup, des détails logiques spécifiques doivent être ajoutés à cause de quoi, où et comment.
Par exemple, dans la méthode de mise en œuvre précédente de «introduire le conteneur», il y a le code suivant:
classe RapportService {// Éliminez la relation de couplage serrée et remplacez-la par le conteneur // Générator privé ReportGenerator STATIC = new pdfGenerator (); // Recherchez le générateur privé ReportGenerator = (ReportGenerator) Container .getBean ("ReportGenerator");
Dans la méthode de mise en œuvre de «introduction du localisateur de services», il y a le code suivant:
classe ServiceLocator {PrivateStatic Container Container = new Container (); publicStatic ReportGenerator getReportGenerator () {// Il s'agit toujours de contener.getBean (), juste un délégué est utilisé return (reportGenerator) contener.getBean ("reportGenerator"); }} classe RAPPORTSERVICE {// RAPPORTSERVICE À la fin, il est toujours «activement» de recherche et de délégués à Servicelocator private ReportGenerator ReportGenerator = ServiceLocator.GetReportGenerator (); }
Solution:
Dans ce cas, le changement «actif» en «passif» réduira sans aucun doute la connaissance interne de Reportservice (c'est-à-dire la logique de la recherche de composants). Selon le principe de l'inversion du contrôle (CIO), cette traction (traction, active) est convertie en mode push (push, passif).
Par exemple, l'abonnement RSS que nous utilisons habituellement est une application push, ce qui nous fait économiser les tracas de vous connecter à notre site préféré plusieurs fois par jour pour obtenir activement des mises à jour d'articles.
L'injection de dépendance (DI) réalise ce type de réception passive et réduit les problèmes des clients (ici, ReportService) lui-même contenant une logique complexe et en sachant trop.
Méthode d'implémentation:
Parce que nous voulons être une réception «passive», nous devons revenir à l'exemple de conteneur sans utiliser le mode de localisation de service. Le diagramme de classe modifié est obtenu à partir de cela comme suit:
Le diagramme de classe d'origine est le suivant. Vous pouvez le vérifier et faire attention aux invites de commentaire:
Implémentation du code:
Afin de permettre à l'exemple d'être compilé et exécuté, et d'utiliser les résultats en cours d'exécution du code de suivi pour instancier explicitement l'ensemble du diagramme de classe et coopérer les uns avec les autres en séquence, de nombreuses instructions d'impression numérotées et deux classes insignifiantes ont été ajoutées au constructeur de chaque classe, ce qui est un peu insultant, comme suit:
import java.util.date; import java.util.hashmap; import java.util.map; // Pour pouvoir compiler et exécuter, il existe deux classes plus insignifiantes. Classe Mois {} Tableau de classe {publicVoid setDate (date de date) {} publicVoid setMonth (mois mois) {}} // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- d'ExcelGenerator ... "); } publicVoid Generate (Table Table) {System.out.println ("Générer un rapport Excel ..."); }} classe PDFGenerator implémente ReportGenerator {public pdfGenerator () {System.out.println ("2 ... Démarrer l'initialisation de pdfGenerator ..."); } publicVoid Generate (Table Table) {System.out.println ("Générer un rapport PDF ..."); }} // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Obtenez et gérez la référence de Reportservice RapportService Reportservice = new Reportservice (); // Injecte l'instance rapportée spécifique créée ci-dessus RAPPORTSERVICE.SETREPORTGERATOR (ReportGenerator); Beans.put ("ReportsService", ReportService); System.out.println ("5 ... End Initialisation Container ..."); } objet publicStatic getBean (String id) {System.out.println ("Last Get Service Component ... GetBean () ->" + ID + "..."); returnBeans.get (id); }} classe reportService {// private static ReportGenerator Generator = new PdfGenerator (); // Éliminez la relation de couplage serrée ci-dessus et remplacez-la par le conteneur // Générateur privé ReportGenerator = (ReportGenerator) Container // .GetBean ("ReportGenerator"); // Supprimez la recherche "active" ci-dessus et fournissez des champs privés pour enregistrer le générateur d'objet injecté injecté à l'injection externe; // Inject PublicVoid de l'extérieur dans Setter Form SetReportGenerator (Generator de ReportGenerator) {System.out.println ("4 ... Démarrer l'injection de rapport de rapport ..."); this.Generator = générateur; } table privée Table = new Table (); public reportService () {System.out.println ("3 ... Démarrer l'initialisation Reportservice ..."); } publicVoid getDailyReport (date de date) {table.setDate (date); générateur. Genèdre (tableau); } publicVoid getMonthlyreport (mois mois) {table.setMonth (mois); générateur. Genèdre (tableau); }} publicClass Client {publicStaticVoid Main (String [] args) {// Initialize the Container New Container (); RAPPORTSERVICE RAPPORTSERVICE = (RAPPORTSERVICE) Container .getBean ("RAPPORTSERVICE"); reportService.getDailyReport (new Date ()); // reportService.getMonthlyReport (new Date ()); }}
Résultats en cours:
1 ... Démarrer le conteneur d'initialisation ... 2 ... Démarrer l'initialisation PDFGenerator ... 3 ... Démarrer l'initialisation Reportservice ... 4 ... Démarrer l'injection RapportGenerator ... 5 ... terminer le conteneur d'initialisation ... Enfin obtenez le composant de service ... getBean () -> RAPPORTSERVICE ... Générez un rapport PDF ...
Avis:
1. Selon l'ordre d'impression des résultats d'exécution ci-dessus, on peut voir que le nombre spécifique ajouté au code est raisonnable, ce qui simule le processus d'exécution du programme, donc ne dessine plus des diagrammes de séquence.
2. Notez que l'utilisation du CIO et du DI dans cet exemple est basée sur ReportService en tant que client (c'est-à-dire le composant DeMander), et le code de test dans la classe du client Main () dans le code est l'utilisateur final du composant de service, mais ce dont il a besoin n'est pas le composant, mais les services dont dispose le composant.
3. En fait, dans le clip de boîte à ressort, l'initialisation du conteneur n'est évidemment pas ce que le client d'utilisateur final doit faire, il doit être démarré à l'avance par le fournisseur de services.
4. Dans le client de l'utilisateur final, nous utilisons toujours CONTERER.GetBean ("Reportservice") pour obtenir à l'avance des composants de service qui ont été instanciés dans le constructeur de conteneurs. Dans des applications spécifiques, les composants de service disponibles sont généralement déployés sur le serveur à l'aide de XML et d'autres fichiers de configuration, puis les fichiers de configuration sont lus par le conteneur et combinés avec une technologie de réflexion pour créer et injecter des composants de service spécifiques.
analyser:
Auparavant, le ReportService demandait activement le composant de service dans le conteneur, mais maintenant il a attendu passivement le composant de service d'injection de conteneur (Inject, c'est-à-dire push). Le contrôle est évidemment transféré du module sous-jacent (ReportService est le composant DeMander) au module de haut niveau (le conteneur est le fournisseur de composants), c'est-à-dire que le contrôle est inversé.