La inyección de dependencias, también conocida como IoC o Inversion of control, es un patrón de diseño que busca facilitar el mantenimiento de aplicaciones muy grandes dividiendo toda la aplicación en componentes separados, de tal manera que ningún otro componente sabe de la implementación concreta del otro ya que todo se hace por medio de interfaces. Forma parte del concepto de “Loose coupling” el cual consiste en que cada componente solo debe conocer la implementación abstracta de otros componentes que utilice, esto se logra usando Interfaces, de esta manera los componentes no dependen de la implementación concreta de otros componentes, ya que siempre y cuando el componente implemente la interface, podrá ser inyectado a través del contenedor de dependencias.
El contenedor de dependencias
También le dicen Kernel en algunos frameworks, y se refiere a la clase que maneja la instanciación de clases e inyección de los componentes en el constructor o a través de propiedades. Uno de los mas populares es Structuremap, pero también esta Ninject que también es bastante conocido. Voy a tratar de darles un ejemplo de en que consiste la inyección de dependencias.
La siguiente clase no utiliza el principio de Loose coupling ni inyección de dependencias:
public class MailerService
{
private MembershipService _membershipService;
private UsersManager _usersManager;
public MailerService()
{
_membershipService = new MembershipService();
_usersManager = new UsersManager();
}
} |
Por que no usa inyección de dependencias ni Loose coupling? Como podrán ver, al crear instancias de mi clases para empezar que el tipo de mi variable es el tipo concreto, es decir MembershipService, al hacer esto prácticamente estamos diciendo que lo que se almacene en esa variable tiene que ser de ese tipo y ahí estamos usnado tight coupling, porque nuestro componente no puede cambiar, si en el futuro nosotros deseamos cambiar la implementación de nuestra clase tenemos que ir a cambiar a todas las clases donde instanciamos este objeto por nuestro nuevo tipo de objeto, digamos que en el futuro nuestro componente MembershipService será reemplazada por otro que se llame OracleMembershipService, esto implicaría ir a cambiar la instanciación en todas las clases lo cual aumenta el mantenimiento y también los bugs que pueden salir como resultado del cambio, ahora vamos esta misma clase pero inyectada:
public class MailerService : IMailerService
{
private readonly IMembershipService _membershipService;
private readonly IUsersManager _usersManager;
public MailerService(IMembershipService membershipService, IUsersManager usersManager )
{
_membershipService = membershipService;
_usersManager = usersManager;
}
} |
El mayor cambio es que ahora usamos interfaces en ves de implementación concretas de nuestros objetos, las cuales pasamos a través del constructor. El contener de inyección de dependencias se encarga de inyecta al constructor las implementaciones concretas que nosotros definamos. En este caso si nosotros queremos cambiar la implementación concreta de MembershipService, solo creamos una nueva clase que implemente nuestra interfase IMemebershipService y cambiar la configuración de contenedor de dependencias para que utilice la nueva clase al inyectar.
Para poder inyectar automáticamente las dependencias la instanciación de nuestra clase deberá hacerse utilizando el contenedor de dependencas, por ejemplo con structuremap se hace de la siguiente manera:
IMailerService mailerService = ObjectFactory.GetInstaces<IMailerService>();
La clase mailerService resultante es inyectada automáticamente con la implementación concreta definidas en la configuración de structuremap.
En otro post voy hablar específicamente de structuremap y como configurarlo, por el momento espero que hayan entendí sobre este patrón. Tengan en consideración no es necesario que en cualquier aplicación utilicen inyección de dependencias, como les mencione es un patrón de disenio que se utiliza en aplicaciones muy grandes para facilitar el mantenimiento de estas, utilizarlo en un proyecto pequeño no tiene ningún o poco beneficio.
La inyección de dependencias también sirve para utilizar TDD(Test driven development), ya que todo el código es completamente testeable, esto también es tema para otro post.