Das gleiche Grundproblem tritt häufig bei objektorientierter Programmierung, Stilregeln und fast allem anderen auf. Es ist möglich - in der Tat sehr häufig -, zu viel Abstraktion zu betreiben, zu viel Indirektion hinzuzufügen und im Allgemeinen gute Techniken übermäßig und an den falschen Stellen anzuwenden.
Jedes Muster oder andere Konstrukt, das Sie anwenden, bringt Komplexität mit sich. Abstraktion und Indirektion streuen Informationen herum, wobei manchmal irrelevante Details aus dem Weg geräumt werden, aber manchmal wird es auch schwieriger, genau zu verstehen, was passiert. Jede Regel, die Sie anwenden, bringt Unflexibilität mit sich und schließt Optionen aus, die möglicherweise der beste Ansatz sind.
Der Punkt ist, Code zu schreiben, der die Arbeit erledigt und robust, lesbar und wartbar ist. Sie sind ein Softwareentwickler - kein Elfenbeinturmbauer.
Relevante Links
http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx
http://www.joelonsoftware.com/articles/fog0000000018.html
Die wahrscheinlich einfachste Form der Abhängigkeitsinjektion (nicht lachen) ist ein Parameter. Der abhängige Code ist von Daten abhängig, und diese Daten werden durch Übergabe des Parameters eingefügt.
Ja, es ist albern und spricht nicht den objektorientierten Punkt der Abhängigkeitsinjektion an, aber ein funktionaler Programmierer wird Ihnen sagen, dass dies (wenn Sie erstklassige Funktionen haben) die einzige Art der Abhängigkeitsinjektion ist, die Sie benötigen. Hier geht es darum, ein triviales Beispiel zu nehmen und die möglichen Probleme aufzuzeigen.
Nehmen wir diese einfache traditionelle Funktion - die C ++ - Syntax ist hier nicht von Bedeutung, aber ich muss sie irgendwie buchstabieren ...
void Say_Hello_World ()
{
std::cout << "Hello World" << std::endl;
}
Ich habe eine Abhängigkeit, die ich extrahieren und injizieren möchte - den Text "Hello World". Leicht genug...
void Say_Something (const char *p_text)
{
std::cout << p_text << std::endl;
}
Wie ist das unflexibler als das Original? Was ist, wenn ich beschließe, dass die Ausgabe Unicode sein soll? Ich möchte wahrscheinlich von std :: cout zu std :: wcout wechseln. Aber das bedeutet, dass meine Saiten dann von wchar_t sein müssen, nicht von char. Entweder muss jeder Aufrufer geändert werden, oder (vernünftigerweise) die alte Implementierung wird durch einen Adapter ersetzt, der die Zeichenfolge übersetzt und die neue Implementierung aufruft.
Das sind genau dort Wartungsarbeiten, die nicht nötig wären, wenn wir das Original behalten hätten.
Und wenn es trivial erscheint, werfen Sie einen Blick auf diese reale Funktion aus der Win32-API ...
http://msdn.microsoft.com/en-us/library/ms632680%28v=vs.85%29.aspx
Das sind 12 "Abhängigkeiten", mit denen man sich befassen muss. Wenn beispielsweise die Bildschirmauflösungen sehr groß werden, benötigen wir möglicherweise 64-Bit-Koordinatenwerte - und eine andere Version von CreateWindowEx. Und ja, es hängt bereits eine ältere Version herum, die vermutlich hinter den Kulissen der neueren Version zugeordnet wird ...
http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx
Diese "Abhängigkeiten" sind nicht nur für den ursprünglichen Entwickler ein Problem. Jeder, der diese Schnittstelle verwendet, muss nachsehen, welche Abhängigkeiten bestehen, wie sie angegeben sind und was sie bedeuten, und herausfinden, was für seine Anwendung zu tun ist. Hier können die Worte "sinnvolle Vorgaben" das Leben viel einfacher machen.
Die objektorientierte Abhängigkeitsinjektion unterscheidet sich im Prinzip nicht. Das Schreiben einer Klasse ist sowohl im Quellcodetext als auch in der Entwicklerzeit ein Overhead. Wenn diese Klasse so geschrieben wird, dass Abhängigkeiten gemäß einigen Spezifikationen für abhängige Objekte bereitgestellt werden, kann das abhängige Objekt diese Schnittstelle nicht unterstützen, selbst wenn dies erforderlich ist um die Implementierung dieses Objekts zu ersetzen.
Nichts davon sollte als Behauptung verstanden werden, dass die Abhängigkeitsinjektion schlecht ist - weit davon entfernt. Aber jede gute Technik kann übermäßig und am falschen Ort angewendet werden. So wie nicht jeder String extrahiert und in einen Parameter umgewandelt werden muss, muss nicht jedes Verhalten auf niedriger Ebene aus Objekten auf hoher Ebene extrahiert und in eine injizierbare Abhängigkeit umgewandelt werden.