El mismo problema básico que a menudo se presenta con la programación orientada a objetos, las reglas de estilo y casi todo lo demás. Es posible, muy común, de hecho, hacer demasiada abstracción y agregar demasiada indirección, y en general aplicar buenas técnicas en exceso y en los lugares equivocados.
Cada patrón u otra construcción que aplique trae complejidad. La abstracción y la indirección dispersan la información, a veces eliminando detalles irrelevantes, pero igualmente a veces dificultan la comprensión exacta de lo que está sucediendo. Cada regla que aplica trae inflexibilidad, descartando opciones que podrían ser el mejor enfoque.
El punto es escribir código que haga el trabajo y sea robusto, legible y mantenible. Usted es un desarrollador de software, no un constructor de torres de marfil.
Enlaces Relevantes
http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx
http://www.joelonsoftware.com/articles/fog0000000018.html
Probablemente la forma más simple de inyección de dependencia (no se ría) es un parámetro. El código dependiente depende de los datos, y esos datos se inyectan al pasar el parámetro.
Sí, es una tontería y no aborda el punto de inyección de dependencia orientado a objetos, pero un programador funcional le dirá que (si tiene funciones de primera clase) este es el único tipo de inyección de dependencia que necesita. El punto aquí es tomar un ejemplo trivial y mostrar los posibles problemas.
Tomemos esta función tradicional simple: la sintaxis de C ++ no es significativa aquí, pero tengo que deletrearla de alguna manera ...
void Say_Hello_World ()
{
std::cout << "Hello World" << std::endl;
}
Tengo una dependencia que quiero extraer e inyectar: el texto "Hola mundo". Suficientemente fácil...
void Say_Something (const char *p_text)
{
std::cout << p_text << std::endl;
}
¿Cómo es eso más inflexible que el original? Bueno, ¿y si decido que la salida debe ser unicode? Probablemente quiera cambiar de std :: cout a std :: wcout. Pero eso significa que mis cadenas deben ser de wchar_t, no de char. O bien cada persona que llama tiene que ser cambiada, o (más razonablemente), la implementación anterior se reemplaza con un adaptador que traduce la cadena y llama a la nueva implementación.
Ese es el trabajo de mantenimiento que no sería necesario si hubiéramos conservado el original.
Y si parece trivial, eche un vistazo a esta función del mundo real desde la API Win32 ...
http://msdn.microsoft.com/en-us/library/ms632680%28v=vs.85%29.aspx
Son 12 "dependencias" con las que lidiar. Por ejemplo, si las resoluciones de pantalla se vuelven realmente enormes, tal vez necesitemos valores de coordenadas de 64 bits, y otra versión de CreateWindowEx. Y sí, ya hay una versión anterior todavía pendiente, que presumiblemente se asigna a la versión más nueva detrás de escena ...
http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx
Esas "dependencias" no son solo un problema para el desarrollador original: todos los que usan esa interfaz tienen que buscar cuáles son las dependencias, cómo se especifican y qué significan, y determinar qué hacer para su aplicación. Aquí es donde las palabras "valores predeterminados razonables" pueden hacer la vida mucho más simple.
La inyección de dependencia orientada a objetos no es diferente en principio. Escribir una clase es una sobrecarga, tanto en texto de código fuente como en tiempo de desarrollador, y si esa clase se escribe para suministrar dependencias de acuerdo con algunas especificaciones de objetos dependientes, entonces el objeto dependiente está bloqueado para admitir esa interfaz, incluso si es necesario para reemplazar la implementación de ese objeto.
Nada de esto debe leerse como afirmando que la inyección de dependencia es mala, ni mucho menos. Pero cualquier buena técnica se puede aplicar en exceso y en el lugar equivocado. Del mismo modo que no todas las cadenas deben extraerse y convertirse en un parámetro, no todos los comportamientos de bajo nivel deben extraerse de los objetos de alto nivel y convertirse en una dependencia inyectable.