Wann Sie DI verwenden und wann Sie sich in Java erstellen müssen


8

Ich habe eine anständige Menge an OOP mit verschiedenen Sprachen, bin aber ziemlich neu in Java.

Ich lese viele Tutorials durch, in denen eine große Anzahl von Objekten im Code einer Klasse erstellt wird, und ich versuche, sie zu durchlaufen, aber in den Tutorials, die Dependency Injection ausführen, Versionen der Klassen zu erstellen, anstatt alle zu instanziieren Klassen selbst.

Aber Java ist nicht wie andere Sprachen, in denen ich so ziemlich alles als Objekt verwendet habe. Wenn ich buchstäblich alles injizieren würde, wäre das Ergebnis sehr chaotisch und schwer zu verfolgen.

Natürlich würden Sie keine String-Objekte injizieren, und ich vermute, es gibt andere Objekte, die Sie nicht injizieren würden, aber ich bin mir nicht sicher, wohin die Linie führen soll. Ab wann ist DI nicht mehr das Richtige und wann wird es zur Belastung? Wie entscheiden Sie pragmatisch, was injiziert und was nur instanziiert werden soll?

Zu Ihrer Information, die Tutorials, die ich mache, sind http://edn.embarcadero.com/article/31995 und http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html zum Erstellen eines einfachen Clients und Server. Ich kopiere sie jedoch nicht Zeile für Zeile, sondern versuche, äquivalente Klassen zu erstellen, die den Best Practices entsprechen


1
Diese Frage ist nicht Java, sondern spricht über Möglichkeiten, alles auf weniger chaotische Weise zu "injizieren": programmers.stackexchange.com/questions/190120/…
JeffO

Antworten:


4

In .Net (was in dieser Hinsicht ähnlich ist, dass alles ein Objekt ist) verwende ich DI hauptsächlich für meine Domänenobjekte (Entitäten, Repositorys und Dienste) und Anwendungsobjekte (Controller, Ansichtsmodelle), sodass Repos / Dienste in den Controller eingefügt werden / Modelle und ähnliches anzeigen. Dies bedeutet, dass meine Geschäfts- und Anwendungslogik vollständig testbar ist. Dies ist der Hauptgrund, warum ich DI verwende.

Grundsätzlich handelt es sich bei den Objekten, in die Sie Inhalte injizieren und injizieren, hauptsächlich um Objekte, die für die von Ihnen erstellte Lösung spezifisch sind. Wenn ein Objekt in der Sprache oder im Framework "native" ist (wie .Net), muss es wahrscheinlich nicht injiziert werden. Viele Objekte benötigen eine Zeichenfolge, um Daten darzustellen, und eine Zeichenfolge ist im Grunde eine "Sprachfunktion", die nicht spezifisch für Ihre Domäne ist. Das Gleiche gilt für Aufzählungen, Listen, Arrays und viele andere Dinge, die sich nicht ändern müssen, wenn Sie Ihre Klasse isoliert vom Rest des Systems ausführen möchten.

Das Wichtigste ist die Kopplung zwischen Ihren Domänen- / Anwendungsklassen. Wenn ein Objekt keine enge Kopplung einführt, ist es normalerweise sicher, es einfach zu erstellen. Eine Möglichkeit, die Kopplung zu überprüfen, besteht darin, zu versuchen, die Methoden in einer Klasse isoliert auszuführen (was im Grunde ein Unit-Test ist). Was DI-ed sein muss, sind alle Abhängigkeiten, die Sie verspotten müssen, um sicherzustellen, dass die Klasse, die Sie testen, wirklich isoliert vom System ausgeführt wird.


Eine andere Sichtweise ist, was Ihre Klasse oder Ihre Methode versucht zu tun? Das klassische Beispiel ist, dass Sie ein Objekt speichern möchten. Die Logik in dieser Klasse / Methode sollte darin bestehen, das Objekt zu speichern, nicht loszufahren und Kesselplattenarbeiten zum Erstellen von Verbindungen usw. auszuführen. Diese Art von Service / Ressource könnte / sollte ausgeführt werden.
Martijn Verburg

4

Erstens ist es in Ordnung, das neue Schlüsselwort wirklich zu verwenden! DI ist eine fantastische Technik, aber es besteht die Versuchung, sie zu überbeanspruchen. Zeiten, in denen Sie DI verwenden möchten, sind:

  • Testdoppel - Oft möchten Sie bei Komponententests eine Ressource eines Drittanbieters verspotten / testen, da Sie diese Ressource eines Drittanbieters nicht aufrufen möchten (z. B. eine vollständige Oracle-Datenbank). Anstatt beispielsweise eine neue Datenbankverbindung zur großen Oracle-Datenbank zu erstellen, möchten Sie diese Verbindung möglicherweise durch eine Verbindung zu einer HSQL-Verbindung (in der Speicherdatenbank) ersetzen.

  • Wenn Sie den Bereich (~ Lebensdauer) dieses Objekts steuern möchten und der natürliche Lebenszyklus von Java-Objekten für Sie nicht funktioniert. Viele Java-basierte DI-Frameworks ermöglichen dies.

  • Wenn Sie Singletons wollen.

  • Immer wenn Sie glauben, eine Fabrik, einen Service Locator oder ähnliches zu benötigen. Dies schließt ein, wenn Sie verschiedene Fabriken benötigen (selten, aber es passiert).

Zu anderen Zeiten erstellen Sie einfach ein neues Objekt. Wenn Sie Zweifel haben, erstellen Sie ein neues Objekt. Sie können es jederzeit ändern, wenn Sie später die Notwendigkeit sehen :-).


Ihr erster Punkt KÖNNTE absolut alles bedeuten, daher bin ich mir nicht sicher, wie Sie die Frage beantwortet haben. Und ich habe viele Orte gesehen, an denen die Verwendung von DI zum Injizieren einer Factory, anstatt zu versuchen, eine Factory über DI zu erstellen, bei weitem die bessere Lösung ist. Daher bin ich auch beim letzten Punkt zweifelhaft.
pdr

Bearbeitet, um die Punkte ein wenig klarer zu machen
Martijn Verburg

Ich habe den Satz "Test Doubles" noch nie gehört. Ich dachte, Sie meinen "test actual docs.oracle.com/javase/6/docs/api/java/lang/Double.html" .
NimChimpsky

1
@NimChimpsky Ein Testdouble ist ein Oberbegriff für einen Mock, Stub oder einen anderen Ersatz. xunitpatterns.com/Test%20Double.html

0

Aus Wikipedia :

Der Hauptzweck des Abhängigkeitsinjektionsmusters besteht darin, die Auswahl zwischen mehreren Implementierungen einer bestimmten Abhängigkeitsschnittstelle zur Laufzeit oder über Konfigurationsdateien anstelle zur Kompilierungszeit zu ermöglichen. Das Muster ist besonders nützlich, um beim Testen Stub-Test-Implementierungen komplexer Komponenten bereitzustellen, wird jedoch häufig zum Auffinden von Plugin-Komponenten oder zum Auffinden und Initialisieren verwendet

Sie sollten keine Zeichenfolgen einfügen müssen, sondern können sie einfach als Parameter an die entsprechende Methode übergeben. Sie sollten keine Daten einfügen müssen, die aus der Konfiguration stammen.

Gute Komponententests helfen Ihnen bei der Lokalisierung von Fehlern. Daher sollten Sie Ihren Code unabhängig von anderen Codeeinheiten testen. DI kann Ihnen dabei helfen.


0

Im Allgemeinen finde ich, dass eine Klasse immer nur newaus einer anderen Klasse stammen sollte.

Dies liegt daran, dass jedes verwendete Objekt newalle Abhängigkeiten der von ihm erstellten Objekte einfügen muss, sobald Sie die Abhängigkeitsinjektion durchlaufen haben. Dies bedeutet, dass das übergeordnete Objekt auch alle diese Abhängigkeiten kennen muss. Wenn Ahat eine Abhängigkeit auf Bund Cerzeugt AInstanzen mit newdann Cautomatisch eine Abhängigkeit von haben muss B, auch wenn Cnie benutzt Bdirekt. Erstens verstößt dies gegen die Trennung von Bedenken, es sei denn C, die einzige Aufgabe besteht darin, As zu erstellen . Andernfalls entsteht ein Problem, wenn Sie jemals eine Abhängigkeit hinzufügen möchten, Ada alle Dinge, die sie erstellen, jetzt dieselbe Abhängigkeit hinzufügen müssen. Damit sollten sie sich wirklich nicht befassen. Es ist besser zu habenCDeklarieren Sie eine Abhängigkeit von AFactoryund AFactoryhaben Sie eine Abhängigkeit von B. Dann können Sie Aallen gewünschten Abhängigkeiten hinzufügen und müssen diese nur AFactorynoch ändern.


-1

"Ab wann ist DI nicht mehr das Richtige und wann wird es zur Last? ..."

Zuallererst mag ich DI und benutze es sehr oft, also versteh mich nicht falsch

DI ist großartig für die Serverseite, aber die Spiele ändern sich insgesamt, wenn es um die Gui-Programmierung geht. Zum Beispiel habe ich Guice in eine vorhandene GUI-App integriert, die in Swing entwickelt wurde

  • Sie müssen viel umgestalten, um Dinge wie statische Fabriken, verschachtelte Abhängigkeiten usw. loszuwerden.
  • Sie müssen sich darüber im Klaren sein, wie DI-Container Objekte erstellen / verarbeiten, z. B. wenn sie beim Start eifrig Objekte erstellen, können Leistungsprobleme auftreten (dies kann eine beliebige App sein, aber insbesondere in GUI-Apps ist eine Verzögerung von 15 bis 40 Sekunden von großer Bedeutung). Sie können die Einstellung tweeken, sofern der DI-Container dies zulässt.
  • Um DI in ein bestehendes Projekt zu integrieren, brauchen Sie Revolution als Evolution

Wie gehe ich mit verschachtelten Abhängigkeiten um?

Angenommen, Sie müssen auf einige Abhängigkeiten in einer tief verschachtelten Klasse zugreifen. Sie können DI auf eine der folgenden Arten verwenden:

  • Ändern Sie den Konstruktor, um eine Konstruktorinjektion zu erhalten (Wissen Sie also, dass der Konstruktor viele Parameter übernimmt ...)?
  • Feldinjektion verwenden (was keine gute Lösung ist, da wir unsere Felder freilegen)
  • Verwenden Sie die Setter-Injektion (wissen Sie also, dass wir unnötige Setter in unserem Code erstellen müssen)

Wie wäre es, wenn Sie Objekt mit neuen () (weil das Objekt Bedarf zur Laufzeit erstellt werden , abhängig von einigen criteris) und wollen es in den Behälter registrieren (Guice Objekte mit neuen nicht Griffe () erstellt erstellt werden soll, das ist gut )? Jetzt müssen Sie sich wieder auf den Container konzentrieren, anstatt neue Funktionen in Ihrer App zu entwickeln.

Abschließende Worte In einigen Fällen können Sie mit DesignPatterns + kreativem Denken und gutem Architekturdesign Situationen vermeiden, in denen das Geld klein ist und die Probleme durch die Einführung von DI groß sind

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.