Dependency Injection: ¿Por qué?

Vamos a empezar esta nueva serie de artículos con una sencilla pregunta:

¿Por qué? ¿Por qué es bueno usar Dependency Injection en mi aplicación?

Vamos a poner un ejemplo imaginario de una clase:

public class MiClase
{
	private MiRepositorio _repo;
	private UnServicio _servicio;

	public Cliente ManejarCliente(int id)
	{
		_repo = new MiRepositorio();
		_servicio = new UnServicio();

		var cliente = _repo.BuscarCliente(id);
		cliente.Tipo = _servicio.AsignarTipoCliente();

		return cliente;
	}
}

Una clase como otra cualquiera… Tiene un método que devuelve un cliente dado un id. Ese cliente lo sacamos de un repositorio y luego le asignamos un Tipo de cliente usando un servicio pensado para ello.

¿Fácil verdad? Es un trozo de código para nada anormal.

Ahora bien, ¿Recordás vuestras clases sobre Programación orientada a objetos? ¿Qué decian? Ah si, que las clases tienen que estar lo más desacopladas posibles entre si.

En este caso, la clase MiClase está acoplada con 2 clases más: MiRepositorio y UnServicio y ya sabemos qué conlleva eso…. Si algún dia queremos cambiar el servicio o el repositorio para pasar de una base de datos a algo más sencillito como un xml, pues tendríamos que ir cambiando las referencias en mil lados.

No solo está ahí el problema… ¿Qué pasaría si quisieramos hacer Unit Test? Pues lloraríamos directamente… ¿Cómo se supone que voy a testear ManejarCliente? La idea está en poder testear componentes de manera aislada, y testear este método implica el uso del repositorio y del servicio. Esto ya arruina el testeo, no solo eso, el repositorio necesita hablar con una base de datos real y si en este caso estamos extrayendo un cliente de dicha base de datos, pues vamos a necesitar un cliente con el que poder jugar en el testeo y que luego no joda la aplicación… Lo suyo sería poder usar una repositorio de mentira en el testeo y así ahorrarnos problemas. Bueno, esto da para un artículo, así que lo dejamos para otro día.

Bueno vale, tenemos una clase muy acoplada con otras, que apenas se puede testear decentemente, que nos haría cambiar mucho código si algún día cambiara los servicios o los repositorios… Vamos, esto no es mantenible ni por asomo.

¿Cómo lo solucionamos? Tal y como piensas… Con Dependency Injection. Gracias a este patrón podemos librarnos de todos esos problemas de una forma muuuy sencilla.

Vamos a ver como se vería nuestra clase si implementaros Dependency Injection en ella:

public class MiClase
{
	private IMiRepositorio _repo;
	private IUnServicio _servicio;

	public MiClase(IMiRepositorio repositorio, IUnServicio servicio)
	{
		_repo = repositorio;
		_servicio = servicio;
	}

	public Cliente ManejarCliente(int id)
	{
		var cliente = _repo.BuscarCliente(id);
		cliente.Tipo = _servicio.AsignarTipoCliente();

		return cliente;
	}
}

Un hombre sabio dijo una vez: Siempre que puedas trabajar con una interfaz hazlo, evita usar implementaciones concretas.

Ahora ya no estamos usando implementaciones concretas, no estamos acoplando el código. Simplemente decimos que necesitamos una implementación de IMiRepositorio y otra de IMiServicio. Tenemos que pasar esas implementaciones en el constructor de la clase, así podemos pasar nuestras propias implementaciones a la hora de hacer unit test. De esta sencilla manera hemos solucionado todos los problemas que he expuesto antes.

Ahora bien… ¿No sigue siendo un problema tener que ir pasando esas implementaciones a cada clase que lo necesite y a mano? No. Existen una multitud de librerías que hacen el trabajo sucio por nosotros. Éstas librerías tienen unos componentes que se llaman Contenedores que son los encargados de suplir todas estas implementaciones a quien las necesite de forma automágica.

Bueno, en los próximos artículos veremos ejemplos reales de Dependency Injection usando WPF y ASP.NET MVC 3.

Tags:

4 comentarios

  1. Buen ejemplo. Me queda clara la idea, evitar dependencia directa entre clases sobretodo a la hora de refactorizar, etc. pero ¿podrías poner un ejemplo más extenso?.

    Por otro lado, hablas de los Unit Test, sería muy interesante una entrada explicativa de ellos con un pequeño ejemplo.

    Un saludo.

  2. Hola de nuevo Javier :)

    Los ejemplos más completos son cosas de verlos en un programa real. Mi programa, Apunta Notas (http://apuntanotas.codeplex.com/) aunque es un programa pequeñito, usa inyección de dependencias y también hace unit test (aunque no está completo). Si te sale alguna duda sobre lo que puedas leer ahi, haz un comentario aquí y te responderé.

    PD: Al intentar actualizar el blog se cargó el charset y parece que todavía hay fallos raros.

  3. Saludos Javier. Buen post…

    No lo creerás, pero desde el año pasado vengo escuchando sobre el patrón de Injeccion de Dependencia, leyendo artículos y viendo ejemplos, todos en ingles. Y hoy entiendo el patron pero no solo eso, se el motivo por el cual utilizarlo que es lo mas importante.

    Excelente explicación muy sencilla y clara, espero que los siguiente post, continúen así.

Dejar un comentario