Ist es angesichts eines Konstruktors, der niemals unterschiedliche Implementierungen mehrerer von ihm initialisierter Objekte verwenden muss, immer noch praktisch, DI zu verwenden? Schließlich möchten wir vielleicht noch einen Unit-Test durchführen.
Die betreffende Klasse initialisiert einige andere Klassen in ihrem Konstruktor, und die von ihr verwendeten Klassen sind ziemlich spezifisch. Es wird niemals eine andere Implementierung verwenden. Sind wir berechtigt, den Versuch zu vermeiden, auf eine Schnittstelle zu programmieren?
Antworten:
Es hängt davon ab, wie sicher Sie sind, dass "nie, nie" richtig ist (während der Zeit, in der Ihre App verwendet wird).
Allgemein:
quelle
Während der Vorteil der Codierung gegenüber einer Schnittstelle ziemlich offensichtlich ist, sollten Sie sich fragen, was genau dadurch erreicht wird, dass Sie dies nicht tun.
Die nächste Frage lautet: Liegt es in der Verantwortung der betreffenden Klasse, die Implementierungen auszuwählen, oder nicht? Das kann der Fall sein oder nicht, und Sie sollten entsprechend handeln.
Letztendlich besteht immer die Möglichkeit, dass eine doofe Einschränkung aus heiterem Himmel kommt. Möglicherweise möchten Sie denselben Code gleichzeitig ausführen, und die Möglichkeit, die Implementierung einzufügen, kann bei der Synchronisierung hilfreich sein. Oder Sie stellen nach der Profilerstellung Ihrer App möglicherweise fest, dass Sie eine andere Zuordnungsstrategie als die einfache Instanziierung wünschen. Oder es treten Querschnittsthemen auf, und Sie haben keine AOP-Unterstützung zur Hand. Wer weiß?
YAGNI empfiehlt, beim Schreiben von Code nichts Überflüssiges hinzuzufügen. Eines der Dinge, die Programmierer ihrem Code hinzufügen, ohne sich dessen bewusst zu sein, sind überflüssige Annahmen. Als "diese Methode könnte nützlich sein" oder "das wird sich nie ändern". Beides verleiht Ihrem Design Unordnung.
quelle
Es hängt von verschiedenen Parametern ab, aber hier sind einige Gründe, warum Sie DI immer noch verwenden möchten:
Fazit: In diesem Fall können Sie wahrscheinlich ohne DI leben, aber es besteht die Möglichkeit, dass die Verwendung von DI zu einem saubereren Code führt.
quelle
Wenn Sie ein Programm oder eine Funktion entwerfen, sollte ein Teil des Denkprozesses sein , wie Sie es testen werden. Abhängigkeitsinjektion ist eines der Testwerkzeuge und sollte als Teil der Mischung betrachtet werden.
Die zusätzlichen Vorteile von Dependency Injection und die Verwendung von Interfaces anstelle von Klassen sind auch bei der Erweiterung einer Anwendung von Vorteil. Sie können aber auch später mithilfe von Suchen und Ersetzen ganz einfach und sicher in den Quellcode nachgerüstet werden. - Auch bei sehr großen Projekten.
quelle
Viele Antworten auf diese Frage können als "Sie könnten es brauchen, weil ..." als YAGNI diskutiert werden, wenn Sie nicht unittesting machen möchten.
Wenn Sie sich fragen, welche Gründe neben Unittests das Programmieren auf eine Schnittstelle erfordern
Ja , Dependency Injection lohnt sich außerhalb von UnitTesting, wenn Sie die Steuerung umkehren müssen . Zum Beispiel, wenn eine Modulimplementierung ein anderes Modul benötigt, auf das in seiner Ebene nicht zugegriffen werden kann.
Beispiel: Wenn Sie die Module haben
gui
=>businesslayer
=>driver
=>common
.In diesem Szenario
businesslayer
kann verwendet,driver
aberdriver
nicht verwendet werdenbusinesslayer
.Wenn Sie
driver
eine höhere Funktionalität benötigen, können Sie diese Funktionalitätbusinesslayer
implementieren, indem Sie eine Schnittstelle incommon
Layer implementieren .driver
muss nur die Schnittstelle in dercommon
Schicht kennen.quelle
Ja, erstens: Vergessen Sie Unit-Tests als Grund, Ihren Code um die Unit-Test-Tools herum zu entwerfen. Es ist niemals eine gute Idee, Ihr Code-Design so zu biegen, dass es einer künstlichen Einschränkung entspricht. Wenn Ihre Tools Sie dazu zwingen, sollten Sie sich bessere Tools besorgen (z. B. Microsoft Fakes / Moles, mit denen Sie viel mehr Optionen zum Erstellen von Scheinobjekten haben).
Würden Sie Ihre Klassen beispielsweise in nur öffentliche Methoden aufteilen, nur weil die Testtools nicht mit privaten Methoden funktionieren? (Ich weiß, dass die vorherrschende Weisheit darin besteht, so zu tun, als müssten Sie keine privaten Methoden testen, aber ich bin der Meinung, dass dies eine Reaktion auf die Schwierigkeit ist, dies mit aktuellen Tools zu tun, und keine echte Reaktion darauf, keine privaten Methoden testen zu müssen.)
Alles in allem kommt es darauf an, was für ein TDDer Sie sind - der "Spötter", wie Fowler ihn beschreibt , muss den Code an die verwendeten Tools anpassen , während die "klassischen" Tester Tests erstellen, die stärker in die Natur integriert sind (dh testen Sie die Klasse als Einheit, nicht jede Methode), sodass weniger Schnittstellen erforderlich sind, insbesondere wenn Sie Tools verwenden, mit denen sich konkrete Klassen verspotten lassen.
quelle
Dependency Injection macht es auch deutlicher , dass Ihr Objekt HAS Abhängigkeiten.
Wenn jemand anderes Ihr Objekt naiv verwendet (ohne auf den Konstruktor zu schauen), wird er feststellen, dass er Dienste, Verbindungen usw. einrichten muss. Dies war nicht offensichtlich, da er sie nicht an den Konstruktor übergeben musste . Durch die Übergabe der Abhängigkeiten wird klarer, was benötigt wird.
Sie verbergen möglicherweise auch die Tatsache, dass Ihre Klasse möglicherweise die SRP verletzt. Wenn Sie in vielen Abhängigkeiten bestehen (mehr als 3), kann Ihre Klasse zu viel tun und sollte überarbeitet werden. Wenn Sie sie jedoch im Konstruktor erstellen, wird dieser Codegeruch ausgeblendet.
quelle
Ich stimme beiden Lagern hier zu und die Angelegenheit steht meiner Meinung nach noch zur Debatte. YAGNI verlangt, dass ich meinen Code nicht so ändere, dass er der Annahme entspricht. Unit-Tests sind hier kein Problem, da ich fest davon überzeugt bin, dass sich die Abhängigkeit niemals ändern wird. Aber wenn ich zu Beginn Unit-Tests durchgeführt hätte, wäre ich ohnehin nie an diesem Punkt angelangt. Als hätte ich mich irgendwann in DI eingeschlichen.
Lassen Sie mich speziell für mein Szenario eine andere Alternative anbieten
Mit einem Factory-Muster kann ich Abhängigkeiten an einem Ort lokalisieren. Beim Testen kann ich die Implementierung basierend auf dem Kontext ändern, und das ist gut genug. Dies widerspricht YAGNI nicht aufgrund der Vorteile der Abstraktion mehrerer Klassenkonstruktionen.
quelle