En primer lugar crearé un primer ejemplo en el que trataré de mostrar qué es eso de la inyección de dependencias, porqué nos puede resultar útil y cómo Ninject puede ayudarnos.
Qué es eso de la inyección de dependencias
Básicamente lo que pretendemos conseguir con la inyección de dependencias es, precisamente, eliminar dependencias. El objetivo es desarrollar las diferentes funcionalidades de nuestra aplicación (clases, métodos, etc) de forma que sean módulos independientes entre sí, precisamente delegaremos en un "contenedor de dependencias" como Ninject la responsabilidad de "inyectar" las dependencias entre dichos módulos (de ahí el nombre). Eliminar esas dependencias permitirá que nuestro código sea mucho más mantenible, extensible y testeable.No se ha entendido nada, ¿verdad? Si al final del artículo vuelves a leer este párrafo todo tendrá mucho más sentido.
Una imagen vale más que mil palabras y un ejemplo más que muchas definiciones, así que, en lugar de enfrascarme con engorrosas definiciones, voy a mostrar un ejemplo en el que veremos cual es el problema que se pretende solucionar y qué tipo de solución propone la inyección de dependencias.
Hola Mundo
Desde el Visual Studio he creado un nuevo proyecto de consola NinjectHelloWorld dentro de una solución llamada Ninject.Como en la mayoría de las aplicaciones "Hola Mundo" el objetivo será mostrar en pantalla precisamente este mensaje.
En el proyecto voy a crear una carpeta Model y dentro de ésta dos archivos Persona.cs/Persona.vb y Mensajes.cs/Mensajes.vb. En el primero crearé la clase Persona que será la responsable de emitir el saludo, mientras que en el archivo Mensajes.cs/Mensajes.vb crearé las clases responsables de formatear el mensaje, por ahora una única clase SaludoMundo.
La clase SaludoMundo expone un método Emitir que escribe el mensaje en la salida de la consola, mientras que la clase Persona crea una instancia de SaludoMundo y expone un método Saludar que llama al método Emitir del saludo.
Para que nuestra aplicación muestre el mensaje deseado simplemente crearé un método MandarSaludo en el archivo Program.cs/Main.vb que cree una instancia de Persona e invoque el método Saludar.
Si arrancamos la aplicación obtendremos el resultado deseado.
Sin embargo si nos fijamos en la clase Persona podremos comprobar que tiene una fuerte dependencia de la clase SaludoMundo. Si nos creásemos, por ejemplo, una nueva clase SaludoTodos en el archivo Mensajes.cs/Mensajes.vb:
y pretendiéramos que este fuese el mensaje a mostrar, deberíamos modificar de forma importante la clase Persona. O si, por ejemplo, creásemos un test unitario para el método Saludar de la clase Persona nada podría garantizarnos, en caso de fallar, que el error se encuentre en la clase Persona y no en la clase SaludoMundo. En este último caso la solución ideal sería el poder crearnos un objeto "Mock" que reemplace al objeto de la clase SaludoMundo a la hora de probar el método Saludar. Es decir, en ambos casos necesitaríamos que la clase Persona nos permitiese utilizar un objeto que no sea necesariamente de la clase SaludoMundo.
La solución es obvia: utilizar interfaces.
Voy a implementar la interfaz IMensaje que expondrá un único método Emitir y que implementarán tanto la clase SaludoMundo como SaludoTodos. En la clase Persona reemplazaré también la referencia a la clase SaludoMundo por la nueva interfaz.
Sin embargo seguimos teniendo una referencia a la clase SaludoMundo en la clase Persona: la llamada al constructor. No podemos crear una instancia de una interfaz por lo que tendremos que buscar alguna alternativa. Lo que voy a hacer es modificar el constructor de la clase Persona para que reciba como parámetro la instancia de un objeto que implemente la interfaz IMensaje. Para ello tendré que cambiar también la llamada al constructor de la clase Persona en el método MandarSaludo.
En esto consiste la inyección de dependencias, más concretamente inyección de dependencias "por constructor", que es uno de los patrones más utilizados. Si, en lugar de modificar el constructor, hubiésemos creado una propiedad pública a través de la cual le asignáramos la instancia de IMensaje, estaríamos hablando de otro patrón diferente conocido como inyección de dependencias "por propiedad".
Artículo siguiente:
Ninject. Hola Mundo (y II). Sacándole partido al contenedor de dependencias
Excelente artículo, había visto ejercicios en donde utilizaban el ninject pero nunca había entendido para qué, en sí hasta llegué a pensar que se estaban complicando la vida. Con esto que ilustras me queda totalmente clara su utilidad
ResponderEliminar?? Pero no veo el uso de ninject
ResponderEliminarEn la segunda parte del artículo se muestra cómo utilizar Ninject en el proyecto de ejemplo
Eliminar