Cómo hacer DI manual con gráficos de objetos profundos y muchas dependencias correctamente

StackOverflow https://stackoverflow.com/questions/2425458

  •  19-09-2019
  •  | 
  •  

Pregunta

Creo que se le ha pedido de alguna u otra manera esta pregunta pero yo no recibo todavía.

Hacemos un proyecto GWT y mi jefe de proyecto no permitido utilizar GIN / Guice como un marco DI (nuevos programadores no van a entender que, según él), así que tratamos de hacer el DI manualmente.

Ahora tengo un problema con gráficos de objetos profundos. La jerarquía de objetos de la interfaz de usuario es el siguiente:

AppPresenter-> DashboardPresenter-> GadgetPresenter-> GadgetConfigPresenter

La forma GadgetConfigPresenter en el árbol jerárquico objeto tiene un par de dependencias como CustomerRepository, ProjectRepository, MandatorRepository, etc.

Así que la GadgetPresenter que crea la GadgetConfigPresenter también tiene estas dependencias y así sucesivamente, hasta el punto de entrada de la aplicación que crea el AppPresenter.

  • ¿Es esta la manera manual de DI se supone que funciona?
  • ¿no significa esto que creo todas las dependencias en el arranque incluso yo no los necesito?
  • sería un marco DI como GIN / Guice ayudarme aquí?
¿Fue útil?

Solución

Usted escribe que

  

GadgetPresenter la que crea el GadgetConfigPresenter [.]

En lugar de crear directamente casos GadgetConfigPresenter, GadgetPresenter debe tomar una dependencia de una fábrica abstracta que puede crear instancias GadgetConfigPresenter por ello. Esto empuja a las dependencias interiores de GadgetConfigPresenter a la fábrica.

Con Constructor de inyección hasta el final, su hombre pobre DI cableado debe ser algo como esto (disculpas por la sintaxis de C #):

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);

Nótese cómo romper la cadena de dependencias a menudo, lo que garantiza que el número de dependencias para cada consumidor nunca llega a ser demasiado grande.

En principio, esto significa que debe crear todas las dependencias en tiempo de arranque, a menos que implemente un perezosa estrategia de carga .

Las cosas tales como la gestión de tiempos de vida son exactamente el tipo de cosa que un DI de contenedores puede ser de gran ayuda, pero es completamente posible escribir una aplicación completa con sólo siguiendo las pautas y principios dI .

En general, sin embargo, aun así, recomendaría un contenedor DI si es posible.

Otros consejos

Se puede hacer uso de interfaces DI contexto. No es difícil, y bastante sencillo.

A interface Context es una clase que expone todas las fijaciones de la configuración del módulo guice.

Este es un ejemplo de esto donde estoy suponiendo que AppPresenter + DashboardPresenter es en un solo paquete y necesita un "contexto", mientras que GadgetPresenter y GadgetConfigPresenter es en otro paquete y necesita otro "contexto". El número de contextos y la forma de manejarlos es enteramente en manos del usuario.

/**
 * 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();
  }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top