Sollte die Verwendung von DI / IoC alle Vorkommen des Schlüsselworts "new" entfernen?

21

Sollte die Verwendung von Dependency Injection und eines Inversion of Control-Containers alle Vorkommen des newSchlüsselworts " " aus Ihrem Code entfernen ?

Mit anderen Worten, sollte jedes Objekt / jede Abhängigkeit, egal wie einfach oder kurzlebig, in Ihrem IoC-Container "registriert" und in die Methode / Klasse injiziert werden, die sie verwenden muss?

Wenn nein, wo ziehen Sie die Linie zwischen den Abhängigkeiten / Objekten, die im IoC-Container registriert werden, und dem, was "in-line" als konkrete Referenz über das newSchlüsselwort erstellt wird?

CraigTP
quelle
Ich hatte den gleichen Gedanken, nach dem Motto "Ist ein 4-Buchstaben-Wort 'neu'?"
Michael Easter

Antworten:

27

Vermeiden Sie Dogmen. Mach was sich richtig anfühlt.

Ich bevorzuge die Verwendung von "new" für Datenstrukturen, die kein Verhalten aufweisen.

Wenn die Klasse Verhalten hat, schaue ich auf den Umfang dieses Verhaltens. Wenn es staatenlos ist und keine Abhängigkeiten hat, neige ich zu "neu". Ich beginne die Umgestaltung in Richtung DI nur, wenn ich eine Abhängigkeit zu statusbehafteten Ressourcen (wie einer Datenbank oder einer Datei) oder zu anderen Klassen mit solchen Ressourcen hinzufügen muss.

Alex Beynenson
quelle
15
+1 für "Dogma vermeiden". Es ist viel zu einfach, in die Falle zu tappen, einfach den Bewegungen zu folgen, ohne zu verstehen, was passiert oder wo es richtig angewendet werden sollte.
Wayne Molina
@Alex Das gefällt mir. Ein sehr pragmatischer Ansatz. Lustigerweise wollte ich meiner Frage einen Code hinzufügen, der eine bestimmte newAbhängigkeit in meinem eigenen Code aufwies , die meine Frage veranlasste. Es war eine einfache Klasse ohne Funktionalität oder "Verhalten" an sich, nur einfache Eigenschaften.
CraigTP
11

In meinem Buch unterscheide ich zwischen stabilen und flüchtigen Abhängigkeiten . Es ist am wichtigsten, DI mit flüchtigen Abhängigkeiten zu verwenden, aber häufig können Sie eine noch lockerere Kopplung erzielen, indem Sie auch stabile Abhängigkeiten abstrahieren und injizieren.

Beachten Sie, dass sich die Anwendung von DI nicht auf einen DI-Container stützen sollte . In dem Fall, in dem Poor Man's DI verwendet wird, werden keine newSchlüsselwörter entfernt - sie werden nur in die Kompositionswurzel verschoben .

Einige Leute bevorzugen tatsächlich Poor Man's DI gegenüber DI Containers. Die Wartungskosten sind zwar höher, dafür erhalten Sie jedoch Sicherheit bei der Kompilierung. Wie ich kürzlich von Dan North gehört habe: " newis the new new" :)

Damit ist lediglich gemeint, dass der Composition Root nicht mit einem DI-Container implementiert wird, sondern nur eine ganze Reihe verschachtelter newAnweisungen enthält.

Mark Seemann
quelle
Markieren Sie, um meinen Twitter-Kommentar ein wenig zu erweitern : Programmierer sind der richtige Ort für konzeptionelle Whiteboard-Fragen, die sich nicht mit einem bestimmten Fehler in einer Implementierung befassen.
Adam Lear
3
Stack Overflow enthält über 2000 Fragen im Abhängigkeitsinjektions-Tag, und viele davon ähneln dieser. Programmierer haben 23 Fragen im selben Tag. Wo sollte ein Entwickler, basierend auf diesen Zahlen, die größte Chance haben, eine Antwort auf eine Frage wie diese zu erhalten?
Mark Seemann
1
Viele dieser Fragen gehen den Programmierern völlig voraus. Diese Seite wurde erstellt, um konzeptionelle Fragen von SO zu lösen und ihnen ein eigenes Zuhause zu geben. Und wir wachsen weiter. Es ist noch in Arbeit, aber im Idealfall werden hier Fragen migriert, die keine spezifischen Implementierungsprobleme beinhalten. Wir tun in der Zwischenzeit, was wir können.
Adam Lear
3

"neu" ist kein verbotenes Schlüsselwort. Meine persönlichen Regeln:

Alle "Dienste" (ich bezeichne einen Dienst als eine Klasse, die eine oder mehrere Methoden für eine und nur eine Sache bereitstellt; zum Beispiel: Zugriff auf die Datenbank, Abrufen / Aktualisieren von Daten für eine bestimmte Domäne) sind im IOC-Container registriert. Keine Klasse sollte die Entscheidung treffen müssen, wie sie die Implementierung eines bestimmten Dienstes erhalten soll, den sie verwenden muss. Wenn Sie einen vorhandenen Dienst verwenden müssen, sollten Sie daher Ihre Klasse und den IOC-Container so konfigurieren, dass er Ihnen zur Verfügung steht. Stellen Sie sich vor, Sie wissen nicht, wie Ihre Implementierung funktioniert, es könnte sich um einen Webdienst handeln, der Ihnen egal ist.

Alle Beans oder Modelle müssen mit dem Schlüsselwort "new" oder mit einer vom IOC registrierten Factory erstellt werden, wenn für sie einige Standardeigenschaften aktiviert sein müssen. Es gibt auch den speziellen Fall von Dienstprogrammklassen, die nur statische Methoden enthalten (zum Beispiel: ein mathematischer Dienstprogrammdienst). Wenn sie völlig eigenständig sind und keine Datenbankverbindung oder einen anderen IOC-registrierten Dienst benötigen, lasse ich sie aus dem IOC aus und sie müssen statisch aufgerufen werden. Wenn eine solche Klasse jedoch einen vorhandenen IOC-registrierten Dienst verwenden muss, ändere ich ihn in eine Singleton-Klasse und registriere ihn im IOC.

Jalayn
quelle
2

Ich möchte nur die vorhandenen Antworten ergänzen, die früher angesprochen wurden, new ist völlig in Ordnung, um Objekte zu erstellen, die reine Wertobjekte sind (dh nur Eigenschaften / Getter / Setter haben). Weitere Informationen finden Sie im Google Testing-Blog .

Jack
quelle
+1 für den Link. Punkt 9 in diesem Blog - Posting die Frage beantwortet und bietet eine pragmatische Unterscheidung zwischen dem, was sollte und soll nicht sein new‚ed
CraigTP
1

Kommt ganz klar auf die Sprache an, die du benutzt. Wenn Ihre Sprache Sie zwingt, Objekte zu verwenden, um sowohl tatsächliche Objekte als auch Datensätze (Wertobjekte, Strukturen) darzustellen, lautet die Antwort höchstwahrscheinlich Nein.

Wenn man nur von "echten" Objekten spricht, ist es nichts Falsches, eine Instanz explizit zu erstellen. Was Sie jedoch bedenken müssen, ist, dass alle Klassen dem Prinzip der Einzelverantwortung folgen sollten. Es sollte nicht die Verantwortung einer Klasse sein, den Implementierer eines Dienstes zu wählen, auf den sie sich verlässt. Es gibt jedoch Klassen, die genau diese Verantwortung haben, dh Implementierer bestimmter Dienste bereitzustellen. Eine IoC könnte eine solche Klasse sein. Tatsächlich ist jede Art von Fabrik eine solche Klasse.

Um es zusammenzufassen: Nur solche Klassen sollten Objekte direkt instanziieren, und es liegt in der Verantwortung, auszuwählen, welche Klassen instanziiert werden sollen.
Diese Kriterien könnten hilfreich sein: http://en.wikipedia.org/wiki/GRASP_(object-oriented_design)#Creator

back2dos
quelle
1

Ein Wort: Nein.

Weitere Wörter: Die Abhängigkeitsinjektion ist genau das. Es ist ein Mittel, mit dem Sie Ressourcen einführen, von denen ein anderes Objekt abhängt, dessen komplizierte Details jedoch nicht aus einer anderen Quelle stammen sollten. Die Verwendung von DI bedeutet nicht, dass NICHTS in Ihrem Programm wissen sollte, wie ein anderes Objekt erstellt wird. Tatsächlich gehe ich davon aus, dass es für ein nicht triviales Programm höchst unmöglich ist, das "neue" Schlüsselwort (oder reflexionsbasierte Alternativen) vollständig zu vermeiden. DI bedeutet jedoch, dass Objekte, die nicht wissen MÜSSEN, wie komplexe Objekte zu erstellen sind, für die eine Vielzahl von Abhängigkeiten erforderlich sind, die dieses Objekt eng mit dem anderen koppeln, nicht über das gesamte Wissen zur engen Kopplung verfügen sollten.

Ich würde die beiden Haupttheorien des O / O-Softwaredesigns, GRASP und SOLID, studieren. GRASP fordert Sie auf, den Zweck des Objekts zu untersuchen und sich zu fragen: "Sollte dieses Objekt für die Erstellung neuer Objekte dieses anderen Typs verantwortlich sein? Ist dieser Teil der 'Jobbeschreibung' dieses Objekts?" SOLID geht einen Schritt weiter: Das "S" steht für das "Single Responsibility Principle", das eindeutig besagt, dass ein Objekt einen Job haben soll und dass es das einzige Objekt im Programm sein soll, das diesen speziellen Job ausführt.

GRASP empfiehlt Ihnen daher im Allgemeinen, Ihre vorhandenen Klassen zu durchsuchen, für die diese neuen Objekte erstellt werden, und eine zu finden, für die die Aufgabe zum Erstellen dieses Objekts mit der bereits durch das Objekt ausgeführten Aufgabe übereinstimmt, wobei der gewünschte Grad an "Kohäsion" beibehalten wird. SOLID wird Ihnen sagen, dass der Zusammenhalt der Schlüssel ist; Die Aufgabe, diese Objekte zu erstellen, sollte einer Fabrik übertragen werden, die in Ihre Klasse eingefügt werden soll. Ich denke, mit der zunehmenden Komplexität Ihres Programms werden Sie feststellen, dass die Einhaltung einer dieser Methoden mit der Bereitschaft zur Umgestaltung zu sehr ähnlichen Architekturen führen wird.

KeithS
quelle