Ich weiß, dass dies eine heiße Debatte ist und dass sich die Meinungen über die Best-Approach-Praxis im Laufe der Zeit ändern.
Ich habe in meinen Kursen ausschließlich Feldinjektionen verwendet, bis ich in verschiedenen Blogs ( z. B . : petrikainulainen und schauderhaft und fowler ) über die Vorteile der Konstruktorinjektion nachgelesen habe . Seitdem habe ich meine Methoden geändert, um Konstruktorinjektion für erforderliche Abhängigkeiten und Setterinjektion für optionale Abhängigkeiten zu verwenden.
Allerdings habe ich vor kurzem in eine Debatte bekommen mit dem Autor von JMockit - ein Mockframework - in dem er Konstruktor & Setter Injektion als schlechte Praxis sieht und zeigt an, dass die JEE Gemeinschaft mit ihm übereinstimmt.
Gibt es in der heutigen Welt eine bevorzugte Art der Injektion? Wird Feldinjektion bevorzugt?
Nachdem ich in den letzten Jahren von Feldinjektion zu Konstruktorinjektion gewechselt bin, finde ich die Verwendung viel klarer, aber ich frage mich, ob ich meinen Standpunkt noch einmal überprüfen sollte. Der Autor von JMockit (Rogério Liesenfeld) ist mit DI klar vertraut, daher fühle ich mich verpflichtet, meinen Ansatz zu überprüfen, da er sich so stark gegen die Injektion von Konstrukteuren / Setzern fühlt.
quelle
Antworten:
Die Feldinjektion ist für meinen Geschmack ein bisschen zu "gruselig in der Ferne" .
Betrachten Sie das Beispiel, das Sie in Ihrem Google Groups-Beitrag angegeben haben:
Sie sagen also im Grunde: "Ich habe diese Klasse mit privatem Status, an die ich
@injectable
Anmerkungen angehängt habe , was bedeutet, dass der Status automatisch von einem Agenten von außen ausgefüllt werden kann, obwohl mein Status als privat deklariert wurde . "Ich verstehe die Gründe dafür. Es ist ein Versuch, einen Großteil der Zeremonie zu vermeiden, die der ordnungsgemäßen Einrichtung einer Klasse innewohnt. Grundsätzlich heißt es: "Ich bin es leid, all dieses Boilerplate zu schreiben, also werde ich einfach meinen gesamten Zustand mit Anmerkungen versehen und den DI-Container sich darum kümmern lassen, es für mich einzustellen."
Es ist eine vollkommen gültige Sichtweise. Es ist jedoch auch eine Problemumgehung für Sprachfunktionen, die möglicherweise nicht umgangen werden sollten. Auch warum dort aufhören? Traditionell hat sich DI darauf verlassen, dass jede Klasse eine Companion-Schnittstelle hat. Warum nicht auch alle diese Schnittstellen mit Anmerkungen entfernen?
Überlegen Sie sich die Alternative (dies wird C # sein, weil ich es besser kenne, aber es gibt wahrscheinlich ein genaues Äquivalent in Java):
Ich weiß schon einiges über diese Klasse. Es ist eine unveränderliche Klasse; state kann nur im Konstruktor gesetzt werden (Referenzen in diesem speziellen Fall). Und weil alles von einer Schnittstelle herrührt, kann ich Implementierungen im Konstruktor austauschen.
Jetzt muss mein DI-Container nur noch über den Konstruktor nachdenken, um zu bestimmen, welche Objekte neu erstellt werden müssen. Aber diese Reflexion wird auf erstklassige Weise über ein öffentliches Mitglied gemacht ; Das heißt, die Metadaten sind bereits Teil der Klasse und wurden im Konstruktor deklariert. Diese Methode hat den ausdrücklichen Zweck, der Klasse die Abhängigkeiten zur Verfügung zu stellen, die sie benötigt.
Zugegeben, das ist eine Menge Boilerplate, aber so wurde die Sprache entworfen. Anmerkungen scheinen ein schmutziger Hack für etwas zu sein, das in die Sprache selbst eingebaut werden sollte.
quelle
VeracodeService
ist fast identisch mit der, die Sie geschrieben haben (allerdings in Java vs C #). DasVeracodeServiceImplTest
ist eigentlich eine Unit Test Klasse. Die@Injectable
Felder sind im Wesentlichen verspottete Objekte, die in den Kontext eingefügt werden. Das@Tested
Feld ist das Objekt / die Klasse mit dem definierten DI-Konstruktor. Ich stimme Ihrer Ansicht zu, dass die Injektion von Konstruktoren der Injektion von Feldern vorgezogen wird. Wie ich bereits erwähnte, empfindet der JMockit-Autor das Gegenteil und ich versuche zu verstehen, warumDas Argument von weniger Testinitialisierungsboiletplate ist gültig, aber es gibt andere Bedenken, die berücksichtigt werden müssen. Zunächst müssen Sie eine Frage beantworten:
Soll meine Klasse nur mit Reflektion instanziierbar sein?
Die Verwendung von Feldinjektionen bedeutet, die Kompatibilität einer Klasse mit Abhängigkeitsinjektionsumgebungen einzugrenzen, die Objekte mithilfe von Reflexion instanziieren und diese bestimmten Injektionsanmerkungen unterstützen. Einige Plattformen, die auf der Java-Sprache basieren, unterstützen nicht einmal Reflection ( GWT ), sodass feldinjizierte Klassen nicht mit ihnen kompatibel sind.
Das zweite Problem ist die Leistung . Ein Konstruktoraufruf (direkt oder durch Reflektion) ist immer schneller als eine Reihe von Reflektionsfeldzuweisungen. Frameworks für die Abhängigkeitsinjektion müssen eine Reflektionsanalyse verwenden, um einen Abhängigkeitsbaum zu erstellen und Reflektionskonstruktoren zu erstellen. Dieser Prozess verursacht zusätzliche Leistungseinbußen.
Die Leistung beeinflusst die Wartbarkeit . Wenn jede Testsuite in einem Abhängigkeitsinjektionsbehälter ausgeführt werden muss, kann ein Testlauf von einigen Tausend Einzeltests mehrere zehn Minuten dauern. Abhängig von der Größe einer Codebasis kann dies ein Problem sein.
Dies alles wirft viele neue Fragen auf:
Im Allgemeinen sind diese Faktoren umso bedeutender, je größer und wichtiger ein Projekt ist. Auch in Bezug auf die Qualität möchten wir den Code im Allgemeinen in Bezug auf Kompatibilität, Testbarkeit und Wartbarkeit hoch halten. Aus philosophischer Sicht unterbricht die Feldinjektion die Kapselung , die eine der vier Grundlagen der objektorientierten Programmierung ist , die das Hauptparadigma von Java darstellt.
Viele, viele Argumente gegen die Feldinjektion.
quelle
Die Feldinjektion erhält von mir ein definitives "Nein".
Wie Robert Harvey ist es für meinen Geschmack etwas zu automagisch. Ich bevorzuge expliziten Code gegenüber impliziten und toleriere Indirektion nur, wenn sie klare Vorteile bietet, da sie das Verständnis und die Argumentation von Code erschwert.
Wie Maciej Chałapuk brauche ich keine Reflektion oder ein DI / IoC-Framework, um eine Klasse zu instanziieren. Es ist wie eine Fahrt nach Rom, um von Amsterdam nach Paris zu gelangen.
Wohlgemerkt, ich liebe DI und all die Vorteile, die es bringt. Nur nicht sicher, ob die Frameworks zum Instanziieren einer Klasse benötigt werden. Vor allem nicht die Auswirkung, die IoC-Container oder andere DI-Frameworks auf den Testcode haben können.
Ich mag es, wenn meine Tests sehr einfach sind. Ich mag es nicht, die Indirektion des Einrichtens eines IoC-Containers oder eines anderen DI-Frameworks durchlaufen zu müssen, damit sie meine Klasse im Test einrichten. Es fühlt sich einfach unangenehm an.
Und das macht meine Tests vom globalen Status des Frameworks abhängig. Das heißt, ich kann nicht mehr zwei Tests parallel ausführen, für die eine Instanz der Klasse X mit unterschiedlichen Abhängigkeiten eingerichtet werden muss.
Zumindest bei der Konstruktor- und Setter-Injection haben Sie die Möglichkeit, die Frameworks und / oder Reflection in Ihren Tests nicht zu verwenden.
quelle
Nun, das scheint eine polemische Diskussion zu sein. Das erste, was angesprochen werden muss, ist, dass sich die Feldinjektion von der Setter-Injektion unterscheidet . Ich arbeite bereits mit einigen Leuten zusammen, die glauben, dass Field and Setter Injection dasselbe ist.
Um es klar zu sagen:
Feldinjektion:
Setterinjektion:
Für mich haben sie jedoch die gleichen Bedenken. Und mein Favorit, die Konstruktorspritze:
Ich habe die folgenden Gründe zu glauben, dass die Konstruktorinjektion besser ist als die Setter- / Feldinjektion (ich zitiere einige Spring-Links, um meinen Standpunkt zu demonstrieren):
@AutoWired
Verbreitung in Ihrem Code ist Ihr Code weniger vom Framework abhängig. Ich weiß, dass die Möglichkeit, das DI-Framework in einem Projekt einfach zu ändern, das nicht rechtfertigt (wer macht das, oder?). Aber dies zeigt für mich einen besseren Code (ich habe dies auf harte Weise mit EJB und Lookups gelernt ). Und mit Spring können Sie die@AutoWired
Annotation sogar mit Konstruktorinjektion entfernen .Wenn Sie nach weiteren Informationen suchen, empfehle ich diesen alten (aber immer noch relevanten) Artikel von Spring Blog, in dem wir erfahren, warum so viele Setter-Injections verwendet werden, und die Empfehlung, Konstruktor-Injections zu verwenden:
Und diese Anmerkung darüber, warum sie glauben, dass Konstruktor besser für Anwendungscode geeignet ist:
Abschließende Gedanken
Wenn Sie sich über den Vorteil des Konstruktors nicht wirklich sicher sind, ist möglicherweise die Idee, Setter (nicht Feld) mit Konstruktorinjektion zu mischen, eine Option, wie vom Spring-Team erläutert :
Aber denken Sie daran, dass die Feldinjektion wahrscheinlich diejenige ist , die unter den dreien vermieden werden sollte .
quelle
Ist es wahrscheinlich, dass sich Ihre Abhängigkeit während des Lebens der Klasse ändert? Verwenden Sie in diesem Fall die Feld- / Eigenschaftsinjektion. Ansonsten Konstruktorinjektion verwenden.
quelle