Le même problème de base que vous rencontrez souvent avec la programmation orientée objet, les règles de style et à peu près tout le reste. Il est possible - très courant, en fait - de faire trop d'abstraction, d'ajouter trop d'indirection et d'appliquer généralement de bonnes techniques de manière excessive et aux mauvais endroits.
Chaque modèle ou autre construction que vous appliquez apporte de la complexité. L'abstraction et l'indirection dispersent les informations, déplaçant parfois les détails non pertinents hors du chemin, mais rendant également parfois plus difficile de comprendre exactement ce qui se passe. Chaque règle que vous appliquez apporte de la rigidité, excluant les options qui pourraient être la meilleure approche.
Le but est d'écrire du code qui fait le travail et qui est robuste, lisible et maintenable. Vous êtes un développeur de logiciels - pas un constructeur de tours d'ivoire.
Liens pertinents
http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx
http://www.joelonsoftware.com/articles/fog0000000018.html
La forme d'injection de dépendance la plus simple (ne riez pas) est probablement un paramètre. Le code dépendant dépend des données, et ces données sont injectées par le biais du passage du paramètre.
Oui, c'est idiot et cela ne traite pas du point d'injection de dépendance orienté objet, mais un programmeur fonctionnel vous dira que (si vous avez des fonctions de première classe), c'est le seul type d'injection de dépendance dont vous avez besoin. Le point ici est de prendre un exemple trivial et de montrer les problèmes potentiels.
Prenons cette simple fonction traditionnelle - la syntaxe C ++ n'est pas significative ici, mais je dois l'épeler en quelque sorte ...
void Say_Hello_World ()
{
std::cout << "Hello World" << std::endl;
}
J'ai une dépendance que je veux extraire et injecter - le texte "Hello World". Assez facile...
void Say_Something (const char *p_text)
{
std::cout << p_text << std::endl;
}
Comment est-ce plus rigide que l'original? Et si je décide que la sortie doit être unicode. Je veux probablement passer de std :: cout à std :: wcout. Mais cela signifie que mes cordes doivent alors être de wchar_t, pas de char. Soit chaque appelant doit être modifié, soit (plus raisonnablement), l'ancienne implémentation est remplacée par un adaptateur qui traduit la chaîne et appelle la nouvelle implémentation.
Il s'agit là de travaux de maintenance qui ne seraient pas nécessaires si nous conservions l'original.
Et si cela semble trivial, jetez un œil à cette fonction du monde réel de l'API Win32 ...
http://msdn.microsoft.com/en-us/library/ms632680%28v=vs.85%29.aspx
C'est 12 "dépendances" à gérer. Par exemple, si les résolutions d'écran deviennent vraiment énormes, nous aurons peut-être besoin de valeurs de coordonnées 64 bits - et d'une autre version de CreateWindowEx. Et oui, il y a déjà une ancienne version qui traîne, qui est probablement mappée à la nouvelle version dans les coulisses ...
http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx
Ces "dépendances" ne sont pas seulement un problème pour le développeur d'origine - tous ceux qui utilisent cette interface doivent rechercher quelles sont les dépendances, comment elles sont spécifiées et ce qu'elles signifient, et déterminer ce qu'il faut faire pour leur application. C'est là que les mots «valeurs par défaut sensibles» peuvent rendre la vie beaucoup plus simple.
L'injection de dépendances orientée objet n'est pas différente en principe. L'écriture d'une classe est une surcharge, à la fois dans le texte du code source et dans le temps du développeur, et si cette classe est écrite pour fournir des dépendances selon certaines spécifications d'objets dépendants, alors l'objet dépendant est verrouillé pour prendre en charge cette interface, même s'il y a un besoin pour remplacer l'implémentation de cet objet.
Rien de tout cela ne doit être interprété comme prétendant que l'injection de dépendance est mauvaise - loin de là. Mais toute bonne technique peut être appliquée de manière excessive et au mauvais endroit. Tout comme toutes les chaînes n'ont pas besoin d'être extraites et transformées en paramètre, tous les comportements de bas niveau ne doivent pas être extraits des objets de haut niveau et transformés en une dépendance injectable.