Recientemente, siempre he estado expuesto a principios o patrones de programación como el COI (inversión de control), DI (inyección de dependencia), y estos son el núcleo de los famosos marcos Java Spring, Struts, etc. En respuesta a esto, revisé varios elementos en Wikipedia y tomé prestados libros relevantes de la biblioteca. Después de leerlos, tengo algo de comprensión. Ahora combinaré las explicaciones en el libro y en mi propio procesamiento y las ordenaré de la siguiente manera:
EG1
Descripción del problema:
Desarrolle un sistema que pueda generar informes en formato Excel o PDF de acuerdo con diferentes requisitos, como informes diarios, informes mensuales, etc.
Solución:
De acuerdo con el principio de "programación orientada a la interfaz", la interfaz y la implementación deben separarse, es decir, la función de generar informes se extrae en un Generador de informes de interfaz general y se proporcionan dos implementaciones que generan informes de Excel y PDF en formatos de Excel y PDF. Luego, el cliente obtiene la función de impresión del informe correspondiente a través del servicio de informes del proveedor de servicios.
Método de implementación:
Según lo anterior, se obtiene el siguiente diagrama de clase:
Implementación del código:
Interface ReportGenerator {public void generate (tabla de tabla); } class ExcelGenerator implementa ReportGenerator {public void generate (tabla de tabla) {System.out.println ("Genere un informe de Excel ..."); }} clase PDFGenerator implementa ReportGenerator {public void generate (tabla de tabla) {System.out.println ("Genere un informe PDF ..."); }} Class Reportservice {// Responsable de crear el generador de informes para necesidades específicas Informe ReportGenerator Generator = new PDFGenerator (); // Generador de Generator de informes estáticos privados = new ExcelGenerator (); public void getDailyReport (fecha de fecha) {table.setDate (fecha); // ... generador.generate (tabla); } public void getMonthlyReport (mes mes) {table.setmonth (mes); // ... generador.generate (tabla); }} Cliente de clase pública {public static void main (string [] args) {informesservice informesservice = new Reportservice (); informesservice.getDailyReport (nueva fecha ()); //reportService.getMonThlyReport(new date ()); }}
EG2
Descripción del problema:
Como se muestra en los comentarios en el código anterior, el generador de informes específico es creado internamente en la clase de servicio de informes, de modo que el servicio de informes se ha basado directamente en PDFGenerator o Excelgenerator, y este obvio acoplamiento estrecho debe eliminarse.
Solución: Introduzca los contenedores para introducir un administrador intermedio, es decir, el contenedor (contenedor), que administra uniformemente los objetos involucrados en el sistema de informes (aquí hay un componente, lo llamamos frijoles), incluidos el servicio de informes y varios generadores XX. Aquí usa una instancia de hashmap en forma de un par de valores clave para guardar estos frijoles.
Método de implementación:
El diagrama de clases se obtiene de la siguiente manera:
Implementación del código:
Container de clase {// Guardar varios componentes requeridos en pares de valores clave mapa estático privado <cadena, objeto> frijoles; Public Container () {Beans = new Hashmap <String, Object> (); // Crear y guardar informes específicos Generador ReportGenerator ReportGenerator = new PDFGenerator (); frijoles.put ("reportGenerator", reportGenerator); // Obtener y administrar la referencia de informes informes informes informesservice = new Reportservice (); Beans.put ("Reportservice", Reportservice); } Public Static Object getBean (ID de cadena) {return beans.get (id); }} Class Reportservice {// Elimina la relación de acoplamiento estricto y reemplazarla con el contenedor // Generador de Generator estático privado = nuevo PDFGenerator (); Generador privado ReportGenerator Generator = (ReportGenerator) Container.getBean ("ReportGenerator"); public void getDailyReport (fecha de fecha) {table.setDate (fecha); generador.generate (tabla); } public void getMonthlyReport (mes mes) {table.setmonth (mes); generador.generate (tabla); }} Cliente de clase pública {public static void main (String [] args) {Container Container = new Container (); Informesservice Reportservice = (Reportservice) Container.getBean ("Reportservice"); informesservice.getDailyReport (nueva fecha ()); //reportService.getMonThlyReport(new date ()); }}
La tabla de sincronización es más o menos como sigue:
Efecto:
Como se mostró anteriormente, el servicio de informes ya no se asocia directamente con el Generador de informes específico. Ha utilizado contenedores para aislar la interfaz y la implementación, mejorando la reutilización de los frijoles componentes del sistema. En este momento, también puede usar archivos de configuración para obtener la definición de componentes específicos en el contenedor en tiempo real.
EG3
Descripción del problema:
Sin embargo, si observa el diagrama de clase anterior, es fácil descubrir que existe una relación bidireccional entre el servicio de informes y el contenedor, y tienen dependencias mutuas. Y, si desea reutilizar el servicio de informes, también depende directamente de la lógica de búsqueda específica de un solo contenedor. Si otros contenedores tienen diferentes mecanismos de búsqueda de componentes (como JNDI), reutilizar el servicio de informes en este momento significa que la lógica de búsqueda interna del contenedor debe modificarse.
Solución: Introducción del localización de servicios
La reintroducción de un localizador de servicio de capa indirecta se utiliza para proporcionar una interfaz para la lógica de búsqueda de componentes. Consulte la descripción en Wikipedia o la descripción de la misma por Java Ee 1 y 2. Esto permitirá el posible aislamiento de posibles cambios.
Método de implementación:
El diagrama de clases es el siguiente:
Implementación del código:
// En la aplicación real, puede usar la interfaz para proporcionar una clase de interfaz unificada SERVICELOCATOR {Container de contenedor estático privado = nuevo Container (); public static ReportGenerator getReportGenerator () {return (reportGenerator) Container.getBean ("ReportGenerAator"); }} Class Reportservice {private ReportGenerator ReportGenerator = ServiceLocator.GetReportGenerator (); // ...}EG4
Descripción del problema:
Sin embargo, ya sea introduciendo contenedor o utilizando el localizador de servicios, Reportservice está "activo" en la búsqueda y creación de componentes específicos, lo que significa que, como cliente, el servicio de informes debe ser claro sobre lo que necesita, dónde se puede obtener y cómo se puede obtener. De repente, los detalles lógicos específicos deben agregarse debido a qué, dónde y cómo.
Por ejemplo, en el método de implementación anterior de 'Introducción del contenedor', existe el siguiente código:
Class Reportservice {// Elimina la relación de acoplamiento estricto y reemplácela con el contenedor // generador de Generator de informes estatales privados = new PDFGenerator (); // encontrar el contenedor privado report de Generator = (report Generator) .getBean ("informarGenerator");
En el método de implementación para 'Introducir el localizador de servicios', existe el siguiente código:
clase ServiceLocator {Container de contenedor privateStatic = New Container (); PublicStatic ReportGenerator getReportGenerator () {// todavía es contenedor.getBean (), solo se usa un delegado return (reportGenerator) contenedor.getBean ("reportGenerAator"); }} Class Reportservice {// Reportservice Al final, todavía se busca y delegará activamente a ServiceLocator privado ReportGenerator ReportGenerator = ServiceLocator.GetReportGenerator (); }
Solución:
En este caso, cambiar 'activo' a 'pasivo' indudablemente reducirá el conocimiento interno del servicio de informes (es decir, la lógica de encontrar componentes). Según el principio de inversión de control (COI), este tirón (Pull, Active) se convierte en un modo de empuje (empuje, pasivo).
Por ejemplo, la suscripción RSS que generalmente usamos es una aplicación push, que nos ahorra la molestia de iniciar sesión en nuestro sitio favorito varias veces al día para obtener activamente actualizaciones de artículos.
La inyección de dependencia (DI) logra este tipo de recepción pasiva y reduce los problemas de los clientes (aquí, Reportservice) que contiene lógica compleja y conociendo demasiado.
Método de implementación:
Debido a que queremos ser una recepción 'pasiva', debemos volver al ejemplo del contenedor sin usar el modo de localización del servicio. El diagrama de clase modificado se obtiene de esto de la siguiente manera:
El diagrama de clase original es el siguiente. Puede consultarlo y prestar atención a las indicaciones de comentarios:
Implementación del código:
Para permitir que el ejemplo se compilue y se ejecute, y para usar los resultados de ejecución del código de seguimiento para instanciar explícitamente todo el diagrama de clase y cooperar entre sí en secuencia, se agregaron muchas declaraciones de impresión numeradas y dos clases insignificantes al constructor de cada clase, que es un bits insulting, como sigue:
import java.util.date; import java.util.hashmap; import java.util.map; // Para poder compilar y ejecutar, hay dos clases más insignificantes. Mes de clase {} Tabla de clases {publicvoid setDate (fecha de fecha) {} publicvoid setmonth (mes mes) {}} // ----------------------------------------------------------------------------------------------------------------------------------------------------------- de ExcelGenerator ... "); } publicvoid generate (tabla de tabla) {System.out.println ("Genere un informe de Excel ..."); }} clase PDFGenerator implementa ReportGenerator {public pdfGenerator () {System.out.println ("2 ... Iniciar inicialización de PDFGenerator ..."); } publicvoid generate (tabla de tabla) {System.out.println ("Genere un informe PDF ..."); }} // ----------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------- Obtenga y administre la referencia de informes informes informes informesservice = new Reportservice (); // Inyectar la instancia específica de InformeGenerator creada anteriormente Reportservice.SetReportGenerator (reportGenerator); Beans.put ("Reportservice", Reportservice); System.out.println ("5 ... Contenedor de inicialización final ..."); } PublicStatic Object getBean (ID de cadena) {System.out.println ("Last Get Service Component ... getBean () ->" + id + "..."); returnbeans.get (id); }} Class Reportservice {// Generador de Generator de Informe estático privado = nuevo PDFGenerator (); // Elimina la relación de acoplamiento apretada anterior y reemplácela con el contenedor // privado informargenerator generador = (informes informeGenerator) Container // .getBean ("ReportGenerator"); // Eliminar la búsqueda "activa" anterior y proporcionar campos privados para guardar el objeto inyectado externamente Generador de Generador de Informe Privado; // Inyect PublicVoid desde el exterior en forma setter setReportGenerator (Generator ReportGenerator) {System.out.println ("4 ... Iniciar Inyect ReportGenerator ..."); this.generator = generador; } tabla privada tabla = nueva tabla (); Public Reportservice () {System.out.println ("3 ... Iniciar Inicialización Reportservice ..."); } publicvoid getDailyReport (fecha de fecha) {table.setDate (fecha); generador.generate (tabla); } publicvoid getMonthlyReport (mes mes) {table.setmonth (mes); generador.generate (tabla); }} PublicClass Client {publicStaticVoid Main (String [] args) {// Inicializar el contenedor nuevo contenedor (); Informesservice Reportservice = (Reportservice) Container .getBean ("Reportservice"); informesservice.getDailyReport (nueva fecha ()); // informesservice.getMonthlyReport (nueva fecha ()); }}
Resultados de ejecución:
1 ... Inicie el contenedor de inicialización ... 2 ... Iniciar inicialización PDFGenerator ... 3 ... Iniciar servicio de informes de inicialización ... 4 ... Inicio Inyect ReportGenerator ... 5 ... Endicalización Fin Contenedor ... Finalmente obtenga el componente de servicio ... GetBean () -> Reportservice ... Genere un informe PDF ...
Aviso:
1. Según el orden de impresión de los resultados de ejecución anteriores, se puede ver que el número específico agregado al código es razonable, lo que simula el proceso de ejecución del programa, por lo que ya no dibuja diagramas de secuencia.
2. Tenga en cuenta que el uso de IOC y DI en este ejemplo se basa en informes de servicio como el cliente (es decir, el componente demander), y el código de prueba en la clase del cliente main () en el código es el usuario final del componente de servicio, pero lo que necesita no es el componente, sino los servicios que tiene el componente.
3. De hecho, en el clip de caja de primavera, inicializar el contenedor obviamente no es lo que el cliente del usuario final debe hacer, el proveedor de servicios debe iniciar de antemano.
4. En el cliente de usuario final, todavía usamos Container.getBean ("Reportservice") para obtener componentes de servicio que se han instanciado en el constructor de contenedores por adelantado. En aplicaciones específicas, los componentes de servicio disponibles generalmente se implementan en el servidor utilizando XML y otros archivos de configuración, y luego los archivos de configuración son leídos por el contenedor y combinados con tecnología de reflexión para crear e inyectar componentes de servicio específicos.
analizar:
Anteriormente, el servicio de informes solicitó activamente el componente de servicio desde el contenedor, pero ahora esperaba pasivamente el componente de servicio de inyección del contenedor (inyectar, es, push). Obviamente, el control se transfiere desde el módulo subyacente (el servicio de informes es el componente demandante) al módulo de alto nivel (el contenedor es el proveedor de componentes), es decir, el control se invierte.