So funktioniert der Hand DI mit tiefen Objektgraphen und viele Abhängigkeiten zu tun richtig
-
19-09-2019 - |
Frage
Ich glaube, diese Fragen wurde in einem oder anderen Art und Weise gefragt, aber ich bin immer noch nicht.
Wir haben ein GWT-Projekt und mein Projektleiter nicht erlaubt zu GIN / Guice als DI Rahmen (neue Programmierer nicht gehen, es zu verstehen, argumentierte er), damit ich versuche zu tun, die DI manuell.
zu verwendenJetzt habe ich ein Problem mit tiefen Objektgraphen. Die Objekthierarchie aus der Benutzeroberfläche sieht wie folgt aus:
AppPresenter-> DashboardPresenter-> GadgetPresenter-> GadgetConfigPresenter
Der GadgetConfigPresenter Weg nach unten der Objekthierarchie Baum hat einige Abhängigkeiten wie CustomerRepository, ProjectRepository, MandatorRepository, etc.
So ist der GadgetPresenter die die GadgetConfigPresenter schaffen auch diese Abhängigkeiten haben und so weiter, bis zum Eintrittspunkt der App, die die AppPresenter erstellt.
- Ist das die Art und Weise manuell DI funktionieren soll?
- bedeutet dies nicht, dass ich alle Abhängigkeiten beim Booten schaffen auch ich sie nicht brauchen?
- wäre ein DI Framework wie GIN / Guice mir helfen hier?
Lösung
Sie schreiben, dass
die GadgetPresenter, die die GadgetConfigPresenter schafft [.]
Statt direkt die Schaffung GadgetConfigPresenter
Fällen GadgetPresenter
sollte nimmt eine Abhängigkeit von einem Abstract Factory dass GadgetConfigPresenter
Instanzen für sie schaffen. Dies drückt die inneren Abhängigkeiten von GadgetConfigPresenter
zur Fabrik.
Mit Constructor Injection den ganzen Weg, Ihre Poor Man DI Verkabelung sollte wie folgt (Entschuldigung für die C # Syntax) aussehen:
var customerRepository = new CustomerRepository(/*...*/);
var projectRepository = new ProjectRepository(/*...*/);
var mandatorRepository = new MandatorRepository(/*...*/);
var gadgetConfigPresenterFactory =
new GadgetConfigPresenterFactory(
customerRepository,
projectRepository,
mandatorRepository);
var gadgetPresenter = new GadgetPresenter(gadgetConfigPresenterFactory);
var dashboardPresenter = new DashboardPresenter(gadgetPresenter);
var appPresenter = new AppPresenter(dashboardPresenter);
Beachten Sie, wie wir bricht die Abhängigkeitskette häufig, um sicherzustellen, dass die Anzahl der Abhängigkeiten für jeden Verbraucher nie zu groß wird.
Im Prinzip bedeutet dies, dass Sie alle Abhängigkeiten beim Booten erstellen müssen, wenn Sie ein faul Beladestrategie .
Solche Dinge wie die Verwaltung von Lebensdauern sind genau die Art von Dingen, wo ein DI Container enorm hilfreich sein kann, aber es ist durchaus möglich, die gesamte Anwendung zu schreiben, indem nur folgende dI Muster und Prinzipien .
Alles in allem aber ich würde immer noch einen DI-Container, wenn überhaupt möglich empfehlen.
Andere Tipps
Sie können DI tun Context Schnittstellen. Es ist nicht schwer, und ziemlich geradlinig.
Ein Context-Interface ist eine Klasse, die alle Bindungen aus der guice Modulkonfiguration aussetzt.
Dies ist ein Beispiel dafür, wo ich gehe davon aus, dass AppPresenter + DashboardPresenter in einem Paket und muss einen „Kontext“, während GadgetPresenter und GadgetConfigPresenter in einem anderen Paket und muss eine anderen „Kontext“. Die Anzahl von Kontexten, und wie sie zu handhaben, liegt ganz an den Benutzer.
/**
* The dependencies that need to be injected for package1
*/
public interface SomePackageContext {
GadgetPresenter getGadgetPresenter();
GadgetConfigPresenter getGadgetConfigPresenter();
}
/**
* The dependencies that need to be injected for package2
*/
public interface OtherPackageContext {
// These methods can take arguments..
AppPresenter getAppPresenter(Args..);
DashboardPresenter getDashboardPresenter(Args..);
}
/**
* All of the DI needed in our project.
*
* <p>We don't need the two interfaces above, we can put
* everything in this interface if we have a small
* project where layering is not a big issue.
*/
public interface PresenterContext
extends SomePackageContext, OtherPackageContext {
}
public class MockPresenterContext implements PresenterContext {
...
}
public class RealPresenterContext implements PresenterContext {
// This is similar to bind(...) in guice
public AppPresenter getAppPresenter(Args..) {
return new AppPresenter(this, otherargs...);
}
public DashboardPresenter getDashboardPresenter(Args..) {
return new DashboardPresenter(this, otherargs...);
}
public GadgetPresenter getGadgetPresenter() {
return new GadgetPresenter(this);
}
public GadgetConfigPresenter getGadgetConfigPresenter() {
return new GadgetConfigPresenter();
}
}
public class DashboardPresenter {
// @Inject
private final GadgetPresenter gadgetPresenter;
/*
* We inject everything using the SomePackageContext.
*/
public DashboardPresenter(SomePackageContext ctxt) {
this.gadgetPresenter = ctxt.getGadgetPresenter();
}
}