Fuera de los marcos de inyección de dependencia, la inyección de dependencia (mediante inyección de constructor o inyección de setter) es casi un juego de suma cero: se reduce el acoplamiento entre el objeto A y su dependencia B, pero ahora cualquier objeto que necesite una instancia de A ahora debe también construye el objeto B.
Redujo ligeramente el acoplamiento entre A y B, pero redujo la encapsulación de A y aumentó el acoplamiento entre A y cualquier clase que deba construir una instancia de A, al acoplarlas también a las dependencias de A.
Por lo tanto, la inyección de dependencia (sin un marco) es igualmente dañina ya que es útil.
Sin embargo, el costo adicional a menudo es fácilmente justificable: si el código del cliente sabe más sobre cómo construir la dependencia que el objeto mismo, entonces la inyección de dependencia realmente reduce el acoplamiento; por ejemplo, un escáner no sabe mucho acerca de cómo obtener o construir una secuencia de entrada para analizar la entrada, o de qué fuente quiere que el código del cliente analice la entrada, por lo que la inyección del constructor de una secuencia de entrada es la solución obvia.
La prueba es otra justificación para poder utilizar dependencias simuladas. Eso debería significar agregar un constructor adicional utilizado para probar solo que permita la inyección de dependencias: si en cambio cambia sus constructores para que siempre requieran inyecciones de dependencias, de repente, debe conocer las dependencias de las dependencias de sus dependencias para construir su dependencias directas, y no puedes hacer ningún trabajo.
Puede ser útil, pero definitivamente debe preguntarse por cada dependencia, ¿vale la pena pagar el beneficio de la prueba y realmente voy a querer burlarme de esta dependencia durante la prueba?
Cuando se agrega un marco de inyección de dependencias, y la construcción de dependencias se delega no al código del cliente sino al marco, el análisis de costo / beneficio cambia enormemente.
En un marco de inyección de dependencia, las compensaciones son un poco diferentes; lo que está perdiendo al inyectar una dependencia es la capacidad de saber fácilmente en qué implementación está confiando, y cambiar la responsabilidad de decidir en qué dependencia está confiando a algún proceso de resolución automatizado (por ejemplo, si necesitamos un Foo @ Inject'ed , debe haber algo que @Provides Foo, y cuyas dependencias inyectadas estén disponibles), o algún archivo de configuración de alto nivel que prescriba qué proveedor debe usarse para cada recurso, o algún híbrido de los dos (por ejemplo, puede ser un proceso de resolución automatizado para dependencias que se pueden anular, si es necesario, usando un archivo de configuración).
Al igual que en la inyección de constructores, creo que la ventaja de hacerlo termina, nuevamente, siendo muy similar al costo de hacerlo: no tiene que saber quién proporciona los datos en los que confía y, si hay múltiples posibilidades proveedores, no tiene que conocer el orden preferido para buscar proveedores, asegúrese de que cada ubicación que necesita los datos verifique para todos los proveedores potenciales, etc., porque todo eso se maneja en un alto nivel por la inyección de dependencia plataforma.
Si bien personalmente no tengo mucha experiencia con los marcos DI, mi impresión es que proporcionan más beneficios que costos cuando el dolor de cabeza de encontrar el proveedor correcto de los datos o el servicio que necesita tiene un costo mayor que el dolor de cabeza, cuando algo falla, de no saber inmediatamente localmente qué código proporcionó los datos incorrectos que causaron una falla posterior en su código.
En algunos casos, otros patrones que oscurecen las dependencias (por ejemplo, localizadores de servicios) ya se habían adoptado (y tal vez también demostraron su valía) cuando aparecieron los marcos DI en la escena, y los marcos DI se adoptaron porque ofrecían alguna ventaja competitiva, como requerir menos código repetitivo, o potencialmente haciendo menos para ocultar al proveedor de la dependencia cuando sea necesario determinar qué proveedor está realmente en uso.