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