No me gusta la inyección de dependencia basada en el constructor.¿Una alternativa viable a la inyección de dependencia?
Creo que aumenta la complejidad del código y disminuye el mantenimiento, y me gustaría saber si hay alguna alternativa viable.
No estoy hablando del concepto de separar la implementación de la interfaz, y tener una forma de resolver dinámicamente (recursivamente) un conjunto de objetos desde una interfaz. Yo apoyo completamente eso. Sin embargo, la forma tradicional de hacer esto basada en el constructor parece tener algunos problemas.
1) Todas las pruebas dependen de los constructores.
Después de usar DI ampliamente en un # proyecto MVC 3 C en el último año, puedo encontrar nuestro código lleno de cosas como esta:
public interface IMyClass {
...
}
public class MyClass : IMyClass {
public MyClass(ILogService log, IDataService data, IBlahService blah) {
_log = log;
_blah = blah;
_data = data;
}
...
}
Problema: Si necesito otro servicio en mi aplicación tengo que modificar el constructor y eso significa que todas las pruebas unitarias para esta clase se rompen.
Incluso las pruebas que no tienen nada que ver con la nueva funcionalidad requieren al menos refactorización para agregar parámetros adicionales e inyectar un simulacro para ese argumento.
Esto parece ser un problema pequeño, y las herramientas automatizadas como el reafilado ayudan, pero ciertamente es molesto cuando un cambio simple como este hace que se rompan más de 100 pruebas. En términos prácticos, he visto a personas haciendo tonterías para evitar cambiar el constructor en lugar de morder la bala y corregir todas las pruebas cuando esto sucede.
2) Las instancias de servicio se transfieren innecesariamente, lo que aumenta la complejidad del código.
public class MyWorker {
public MyWorker(int x, IMyClass service, ILogService logs) {
...
}
}
Creación de una instancia de esta clase si sólo es posible si estoy dentro de un contexto en que los servicios prestados están disponibles y automáticamente se han resuelto (por ejemplo. Controlador) o, por desgracia, pasando la instancia de servicio por varias cadenas de clases de ayuda.
veo código como este todo el tiempo:
public class BlahHelper {
// Keep so we can create objects later
var _service = null;
public BlahHelper(IMyClass service) {
_service = service;
}
public void DoSomething() {
var worker = new SpecialPurposeWorker("flag", 100, service);
var status = worker.DoSomethingElse();
...
}
}
En caso de que el ejemplo no es clara, lo que estoy hablando es de pasar instancias de interfaz DI resueltos a través de múltiples capas de ninguna razón que no sea en la capa inferior que se necesitan para inyectar en algo.
Si una clase no depende de un servicio, debe tener una dependencia en ese servicio. Esta idea de que existe una dependencia "transitoria" en la que una clase no usa un servicio , sino que simplemente la transfiere es, en mi opinión, una tontería.
Sin embargo, no conozco una solución mejor.
¿Hay algo que proporcione los beneficios de DI sin estos problemas?
he contemplado el uso del marco DI dentro de los constructores en su lugar ya que esto resuelve un par de problemas:
public MyClass() {
_log = Register.Get().Resolve<ILogService>();
_blah = Register.Get().Resolve<IBlahService>();
_data = Register.Get().Resolve<IDataService>();
}
¿Hay alguna desventaja de hacer esto?
Significa que las pruebas unitarias deben tener "conocimiento previo" de la clase para unir mocks para los tipos correctos durante el inicio de la prueba, pero no puedo ver ningún otro inconveniente.
NB. Mis ejemplos están en C#, pero también me he topado con los mismos problemas en otros idiomas, y especialmente los idiomas con soporte de herramientas menos maduros, estos son grandes dolores de cabeza.
si lo coloca dentro del constructor crea una dependencia en el componente di usado. si pasas las interfaces al constructor puedes cambiar el componente di, digamos Autofac con NInject o Castle, etc. Así que si realmente estás realmente seguro de que nunca cambiarás el componente di usado y quédate encendido digamos Autofac, esta es una solución muy viable. –