Patrón de Inyección de dependencias

Patrón de Inyección de dependencias

 

Patrón de Inyección de dependencias. 1

Introducción. 1

Diseños tradicionales. 2

Diseñando nuestro patrón de inyección de dependencias DependencyInyector. 2

Esquema de funcionamiento. 3

Ejemplo de implementación en Java 5. 3

Init.java. 3

InstanceA.java. 3

InstanceB.jave. 4

DependencyInjector.java. 4

InstanceConfigurationReader.java. 5

InstanceConfiguration.java. 6

ParameterConfiguration.java. 7

InstanceCrearor.java. 7

InstanceConfigurator.java. 8

Instance-Config.xml 9

Conclusión. 10

 

  English Version: The dependency Injector Pattern

Introducción

En el desarrollo de software moderno se ha comenzado a generalizar el uso de patrones para implementar partes de nuestros desarrollos. Los patrones proponen soluciones estándares a los problemas comunes de diseño de nuestras aplicaciones. Hay muchos patrones diferentes, aunque sin duda los más famosos son los conocidos como patrones “GoF”.

Realmente podemos  definir nosotros mismos otros patrones , siempre que encontremos una solución estándar a un problema común.

 

 

En este artículo os voy a mostrar un patrón muy sencillo, el patrón “inyector de dependencias”, muy utilizado últimamente en los desarrollos de software modernos, sobre todo en el mundo “Open Source” de Java. Este patrón a su vez deriva de uno más genérico, el patrón de “inversión del control” de Larman.

 

Como siempre, lo primero que vamos a describir es el problema.  El escenario del que vamos a partir es el siguiente:

·       Una clase A está implementando una cierta funcionalidad de la aplicación. Como ejemplo podría ser una cierta funcionalidad de la lógica de negocio.

·       Para completar dicha funcionalidad usa una clase B de utilidad. Es el caso habitual de las clases que implementan la persistencia de los objetos en la base de datos.

·       Para realizar su función, la clase B utiliza otra clase S que le permite el acceso a otros recursos, en nuestro ejemplo será la clase de conexión al gestor de la base de datos.

 

Diseños tradicionales

Normalmente en los diseños habituales, la clase B de utilidad tiene una relación de uso de la clase S, por lo que para poder utilizarla debe cumplir dos cosas:

  • debe conocer su tipo
  • debe poder obtener una instancia de la clase S.

 

Esto introduce una relación de dependencia, al menos en la dirección B->S, entre ambas clases. Para poder minimizar el impacto de dicha dependencia podemos recurrir a varias soluciones.

  • Con respecto al tipo, podemos utilizar el patrón de Interfaz para la clase S, es decir, que B conocerá una interfaz genérica de la clase S, lo que aisla a la clase B de la implementación real de la clase S.
  • Ahora nos queda la segunda parte del problema, y es el modo en el que B obtiene una instancia de la clase S.  Aquí nos va a ayudar el patrón de inversión de control, que nos dice que la instancia de la clase S le será pasada por la clase A, es decir, los objetos que B necesita para completar la petición de A le son pasados a B como parámetros de la petición. El control sobre el objeto S pasa de la clase llamada B a la clase llamadora A, es decir, se ha invertido el control de la clase S.

 

Diseñando nuestro patrón de inyección de dependencias DependencyInyector

Podemos crear una versión sencilla de este patrón utilizando un diseño bastante simple.

Este patrón lo vamos a descomponer en los siguientes objetos:

  1. DependencyInyector. Es el objeto que controla cómo se realiza la inyección de dependencias. Utiliza los objetos DependencyConfigarationReader, InstanceCreator e InstanceConfigurator. La configuración de las instancias la almacena en el mapa de  instanceConfugurations y las instancias en el mapa instances.
  2. InstanceConfigurationReader. Este objeto lee la configuración de dependencias que se va a utilizar. Esta configuración está compuesta de una serie de objetos que se deben instanciar, la lista de parámetros con su valores que se debe proporcionar a cada objeto para su configuración y las relaciones que se deben crear entre los diferentes objetos.
  3. InstanceCreator. Este es un objeto que sigue el patrón factoría, y se ocupa de crear instancias y ponerlas a disposición de los demás objetos del patrón.
  4. InstanceConfigurator. Este objeto conoce cómo se debe configurar cada uno de los objetos instanciados, asignándole los parámetros y relaciones.

 

 

En el diagrama se puede ver el diseño básico del patrón. La clase principal DependencyInyector sirve como interfaz para el conjunto. El usuario interactuará con el conjunto a través de esta clase. Para diseñar esta clase podemos usar el patrón singleton, ya que normalmente nos hará falta una única instancia de la misma.

Esquema de funcionamiento

Al instanciar un inyector de dependencias, este objeto usa el objeto InstanceConfiguratorReader para que éste obtenga la información de dependencias a utilizar. A continuación se instancia un objeto InstanteCreator para que se puedan crear las instancias de objetos solicitadas. Luego el DependencyInyector crea una instancia del DependencyConfigurator y le pasa a esta instancia las referencias a los otros objetos instanciados (inversión de control en esta instancia, como se puede ver). Ahora es el DependencyConfigurator el responsable de ir creando instancias de objetos, mediante el InstanceCreator, y luego irlas configurando, según las instrucciones que reciba del DependencyConfiguration.

Ejemplo de implementación en Java 5

Para ilustrar el patrón DependencyInjector he creado una implementación simple en Java 5. Esta implementación se puede probar de una manera muy sencilla sin más que crear un proyecto Java en nuestro entorno de desarrollo y añadir los siguientes ficheros:

 

Init.java

 

Esta es la clase que crea la instancia del inyector de dependencias.  Una vez instanciadas la clase InstanciaA y InstanciaB muestra su contenido. Es un ejemplo simple.

 

InstanceA.java

InstanceB.jave

 

Clases de ejemplo.

DependencyInjector.java

 

La clase DependencyInjector, responsable de coordinar la inyección de dependencias.

InstanceConfigurationReader.java

 

Clase simple para leer la información de configuración de las dependencias.  Lee la información almacenada en un sencillo fichero XML.

 

InstanceConfiguration.java

 

Java Bean para para amacenar la información de configuración de dependencias.

 

ParameterConfiguration.java

 

Clase auxiliar del bean de configuración.

InstanceCrearor.java

 

Creador de instancias. Para este ejemplo he usado una factoría abstracta muy simple.

InstanceConfigurator.java

 

Configurador de instancias. Utiliza la información de configuración para inyectar parámetros y dependencias de otras clases. Utiliza el mecanismo de reflexión de Java.

Instance-Config.xml

 

Fichero de configuración de las instancias.

 

Conclusión

 

En este artículo hemos visto cómo utilizar el patrón de inyector de dependencias, que nos permite crear instancias de objetos y configurarlas, aislando las dependencias entre los mismos mediante la inyección de las instancias de otros objetos como parámetros de los objetos.

Además hemos visto una implementación simple del patrón, en Java 5, que nos permitirá añadir de manera sencilla un inyector de dependencias a nuestros proyectos. El proceso de instanciación de los diferentes objetos que componen nuestro sistema o aplicación se controlará mediante un simple ficheo xml, lo que nos permitirá modificar la configuración del mismo sin más que utilizar diferentes ficheros xml.

Este patrón nos resolverá de una manera sencilla y elegante el ensamblado de componentes dentro de nuestra aplicación.

Además con este artículo entenderemos mejor el esquema de funcionamiento de los contenedores de objetos actuales, como puede ser Spring Framework y otros.