352 Stimmen

Was sind die Nachteile bei der Verwendung von Dependency Injection?

Ich versuche, DI als Muster hier bei der Arbeit einzuführen, und einer unserer leitenden Entwickler würde es gerne wissen: Was - wenn überhaupt - sind die Nachteile zur Verwendung des Dependency Injection-Musters?

Bitte beachten Sie, dass es mir hier um eine - möglichst vollständige - Liste geht, nicht um eine subjektive Diskussion zu diesem Thema.


Klärung : Ich spreche über die Dependency Injection Muster (siehe dieser Artikel von Martin Fowler), no ein bestimmtes Framework, sei es XML-basiert (wie Spring) oder codebasiert (wie Guice), oder "selbstgesteuert".


bearbeiten : Einige großartige weitere Diskussionen / Tiraden / Debatten /r/programmierung hier.

42voto

29voto

Anthony Punkte 5038

Code ohne DI birgt das bekannte Risiko, sich zu verheddern in Spaghetti-Code - Einige Symptome sind, dass die Klassen und Methoden zu groß sind, zu viel tun und nicht einfach geändert, zerlegt, refaktorisiert oder getestet werden können.

Häufig verwendeter Code mit DI kann Ravioli-Code wo jede kleine Klasse wie ein einzelnes Ravioli-Nugget ist - sie macht eine kleine Sache und die Grundsatz der einzigen Verantwortung eingehalten wird, was gut ist. Aber wenn man die Klassen für sich betrachtet, ist es schwer zu erkennen, was das System als Ganzes tut, da es davon abhängt, wie all diese vielen kleinen Teile zusammenpassen, was schwer zu erkennen ist. Es sieht einfach wie ein großer Haufen kleiner Dinge aus.

Indem man die Spaghetti-Komplexität großer, gekoppelter Codestücke innerhalb einer großen Klasse vermeidet, läuft man Gefahr, eine andere Art von Komplexität zu erzeugen, bei der es viele einfache kleine Klassen gibt und die Interaktionen zwischen ihnen komplex sind.

Ich denke nicht, dass dies ein fataler Nachteil ist - DI ist immer noch sehr lohnenswert. Ein gewisses Maß an Ravioli-Stil mit kleinen Klassen, die nur eine Sache tun, ist wahrscheinlich gut. Selbst im Übermaß ist es meiner Meinung nach nicht so schlimm wie Spaghetti-Code. Aber sich bewusst zu sein, dass man es zu weit treiben kann, ist der erste Schritt, es zu vermeiden. Folgen Sie den Links, um zu erfahren, wie man es vermeiden kann.

14voto

Joey Guerra Punkte 536

Die Illusion, dass Sie Ihren Code entkoppelt haben, nur weil Sie Dependency Injection implementieren, ohne ihn WIRKLICH zu entkoppeln. Ich denke, das ist das Gefährlichste an DI.

13voto

ckittel Punkte 6191

Eine Sache, die mich bei DI ein wenig stutzig macht, ist die Annahme, dass alle injizierten Objekte billig zu instanziieren y keine Nebenwirkungen haben -Oder- die Abhängigkeit wird so häufig verwendet, dass sie die damit verbundenen Instanziierungskosten überwiegt.

Dies kann vor allem dann von Bedeutung sein, wenn eine Abhängigkeit nicht häufig die innerhalb einer konsumierenden Klasse verwendet werden, wie z. B. eine IExceptionLogHandlerService . Offensichtlich wird ein Dienst wie dieser innerhalb der Klasse (hoffentlich :)) nur selten aufgerufen - vermutlich nur bei Ausnahmen, die protokolliert werden müssen; dennoch ist die Kanonisches Konstruktor-Injektionsmuster ...

Public Class MyClass
    Private ReadOnly mExLogHandlerService As IExceptionLogHandlerService

    Public Sub New(exLogHandlerService As IExceptionLogHandlerService)
        Me.mExLogHandlerService = exLogHandlerService
    End Sub

     ...
End Class

...erfordert, dass eine "Live"-Instanz dieses Dienstes zur Verfügung gestellt wird, ungeachtet der Kosten/Nebeneffekte, die erforderlich sind, um ihn zu erhalten. Nicht, dass es wahrscheinlich wäre, aber was wäre, wenn die Erstellung dieser Abhängigkeitsinstanz einen Dienst-/Datenbanktreffer oder Nachschlagen in Konfigurationsdateien mit sich brächte oder eine Ressource sperrt, bis sie entsorgt wird? Wenn dieser Dienst stattdessen nach Bedarf, service-located oder factory-generated (die alle ihre eigenen Probleme haben) konstruiert wurde, dann würden Sie die Baukosten nur bei Bedarf übernehmen.

Nun ist es ein allgemein akzeptierter Grundsatz des Software-Designs, dass die Konstruktion eines Objekts est billig und nicht Nebenwirkungen hervorrufen. Das ist zwar ein schöner Gedanke, aber nicht immer der Fall. Die Verwendung von typischer Konstruktor-Injektion setzt jedoch voraus, dass dies der Fall ist. Das heißt, wenn Sie eine Implementierung einer Abhängigkeit erstellen, müssen Sie sie mit DI im Hinterkopf entwerfen. Vielleicht hätten Sie die Objektkonstruktion teurer gemacht, um an anderer Stelle Vorteile zu erzielen, aber wenn diese Implementierung injiziert werden soll, werden Sie wahrscheinlich gezwungen sein, dieses Design zu überdenken.

Bestimmte Techniken können übrigens genau dieses Problem entschärfen, indem sie das "Lazy-Loading" von injizierten Abhängigkeiten ermöglichen, z. B. indem sie einer Klasse eine Lazy<IService> Instanz als die Abhängigkeit. Dies würde die Konstruktoren Ihrer abhängigen Objekte ändern und dazu führen, dass Sie noch mehr über Implementierungsdetails wie die Kosten für die Objektkonstruktion wissen, was wohl auch nicht wünschenswert ist.

13voto

Anurag Punkte 136648

Bei einer selbstentwickelten Lösung sind die Abhängigkeiten direkt im Konstruktor zu sehen. Oder vielleicht als Methodenparameter, was wiederum nicht allzu schwer zu erkennen ist. Allerdings können vom Framework verwaltete Abhängigkeiten, wenn man sie auf die Spitze treibt, wie Magie wirken.

Zu viele Abhängigkeiten in zu vielen Klassen sind jedoch ein klares Zeichen dafür, dass die Klassenstruktur nicht stimmt. In gewisser Weise kann Dependency Injection (selbst entwickelt oder vom Framework verwaltet) dazu beitragen, eklatante Design-Probleme aufzudecken, die sonst vielleicht im Dunkeln lauern würden.


Um den zweiten Punkt besser zu veranschaulichen, hier ein Auszug daraus Artikel ( Originalquelle ), was meiner festen Überzeugung nach das grundlegende Problem beim Aufbau jedes Systems ist, nicht nur bei Computersystemen.

Nehmen wir an, Sie wollen einen College-Campus entwerfen. Sie müssen einen Teil der Planung an die Studenten und Professoren delegieren, sonst wird das Physikgebäude nicht gut für die Physiker funktionieren. Kein Architekt weiß genug darüber, was die Physiker brauchen, um das alles selbst zu machen. Aber man kann nicht die Gestaltung jedes einzelnen Raumes an die Bewohner delegieren, denn dann hat man einen riesigen Schutthaufen.

Wie kann man die Verantwortung für das Design auf alle Ebenen einer großen Hierarchie verteilen und gleichzeitig die Konsistenz und Harmonie des Gesamtdesigns aufrechterhalten? Dies ist das architektonische Designproblem, das Alexander zu lösen versucht, aber es ist auch ein grundlegendes Problem der Computersystementwicklung.

Kann DI dieses Problem lösen? Nein . Aber es hilft Ihnen, klar zu sehen, wenn Sie versuchen, die Verantwortung für die Gestaltung jedes Raumes an seine Bewohner zu delegieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X