viernes, 11 de septiembre de 2015

Inyección de dependencias

En esta entrada no pretendo dar una clase magistral o completa sobre lo que es la inyección de dependencias. Pero, por si algún intrépido lector ha llegado hasta esta entrada y quiere seguir leyendo las siguientes, recordaré el concepto de inyección de dependencias porque lo utilizaremos más adelante.

Este concepto lo utilizó hace mucho tiempo Martin Fowler y en pocas palabras lo que pretende es evitar los acoplamientos de un objeto con otro. Voy a poner un ejemplo.

Imaginemos que tenemos este controller en nuestra aplicación ASP .NET MVC.

public class LoginController : Controller
{
 public ActionResult Index(UserEntity User)
        {
            UserService UserSer = new UserService();
            UserEntity oUser;
            try
            {
                oUser = UserSer.DoLogin(User.UserName, User.Pass);
                if (oUser != null)
                {                
                    FormsAuthentication.SetAuthCookie(User.UserName, false);
                    SessionHelper.CurrentUser = oUser;
                    return RedirectToAction("Index", "History");
                }
            }
            catch (Exception ex)
            { }

            ModelState.AddModelError("", "Los datos de acceso son incorrectos.");

            return View(User);
        }

 public ActionResult Register(UserEntity User)
        {
            UserService UserSer = new UserService();
            try
            {
                oUser = UserSer.Register(User);
                return RedirectToAction("Index", "History");
            }

            catch (Exception ex)
            { }        

            return View(User);
        }
}


El controller es correcto en cuanto a la funcionalidad. Hace lo que se supone que tiene que hacer, pero podemos observar varias cosas:
- Nuestro controller está acoplado a la clase UserService.
- No cumplimos con el principio DRY (mucho código repetido)
- Difícil poder hacer pruebas unitarias a los métodos.


Vamos a hacer unos pequeños cambios para intentar mejorar la situación
public class LoginController : Controller
{
 private UserService UserSer;
 public LoginController()
{
       UserSer = new UserService();
}
 public ActionResult Index(UserEntity User)
        {          
            UserEntity oUser;
            try
            {
                oUser = UserSer.DoLogin(User.UserName, User.Pass);
                if (oUser != null)
                {                
                    FormsAuthentication.SetAuthCookie(User.UserName, false);
                    SessionHelper.CurrentUser = oUser;
                    return RedirectToAction("Index", "History");
                }
            }
            catch (Exception ex)
            { }

            ModelState.AddModelError("", "Los datos de acceso son incorrectos.");

            return View(User);
        }

 public ActionResult Register(UserEntity User)
        {
            try
            {
                oUser = UserSer.Register(User);
                return RedirectToAction("Index", "History");
            }

            catch (Exception ex)
            { }        

            return View(User);
        }
}


Bueno; hemos mejorado un poco quitando la instanciación de la clase UserService de cada método y llevándolo sólo al constructor del controller.
Pero seguimos teniendo el controller acoplado al objeto UserService y seguimos teniendo difícil el realizar pruebas unitarias debido a este acoplamiento.

Inyección de Dependencias.
Para evitar este acoplamiento utilizaremos la Inyección de Dependencias y el uso de interfaces.
Lo primero que deberemos hacer es extraer la interface de la clase UserService.
En este caso, sería algo así

public interface IUserService
    {

        UserEntity DoLogin(string Username, string Pass);
        UserEntity Register(UserEntity User);
}

Una vez hecho esto, lo que hay que decirle a la clase UserService, es que implementa esta interface.

 public class UserService : IUserService
{
/// Codigo propio de esta clase
}


Y cómo afecta esto a nuestro controller? Bien, veamos

public class LoginController : Controller
{
 private IUserInterface UserSer;
 public LoginController(IUserInterface UserServInyectado)
{
       UserSer = UserServInyectado;
}


Si nos fijamos, no queda ningún rastro de la clase UserService. Ahora solo utilizamos interfaces. Cualquier clase que implemente la interface IUserInterface será válida como parámetro del constructor de nuestro controller.

Este sistema se llama inyección de dependencias por constructor, ya que es en el constructor de nuestro objeto cuando inyectamos el "comportamiento" deseado.

¿Y quién proporciona las dependencias a nuestro controller?. Bueno eso lo veremos en la próxima entrega de Contenedores de Inversión de Control.

No hay comentarios:

Publicar un comentario