2010-03-11 9 views
7

Creo que esta pregunta ha sido formulada de una u otra forma, pero todavía no lo entiendo.Cómo hacer manual DI con gráficos de objetos profundos y muchas dependencias correctamente

Hacemos un proyecto GWT y mi líder de proyecto no puede usar GIN/Guice como un marco DI (los nuevos programadores no van a entenderlo, argumentó) así que trato de hacer el DI manualmente.

Ahora tengo un problema con los 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.

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

  • ¿Es así como se supone que el manual DI funciona?
  • ¿no significa esto que creo todas las dependencias en el momento del inicio aunque no las necesito?
  • ¿me ayudaría un marco de DI como GIN/Guice aquí?
+2

Parece que el problema es el liderazgo de su proyecto más que nada. No puede usar una tecnología porque un nuevo programador no la entenderá? ¿Qué hay de documentarlos y entrenarlos sobre qué entender? –

+0

@matt: él es bastante reacio a las nuevas tecnologías y cree que un nuevo programador necesita aprender mucho en este proyecto como el puente java a php y luego el DI es solo una magia entre bastidores que no obtendrán. no lo creo realmente ... si un marco DI es la única solución, intentaré de nuevo convencerlo, pero estaría realmente interesado si y cómo se hace manualmente. – Fabian

+1

Recomendaría abordar esta discusión como "ver todo el trabajo de cableado manual que tenemos que hacer en el código, y compararlo con cuánto más fácil es usar un contenedor IoC" –

Respuesta

8

Usted escribe que

la GadgetPresenter que crea el GadgetConfigPresenter [.]

En lugar de crear directamente GadgetConfigPresenter casos, debe GadgetPresentertake a dependency on an Abstract Factory que pueden crear instancias GadgetConfigPresenter por ello. Esto empuja a las dependencias internas de GadgetConfigPresenter a la fábrica.

Usando Constructor inyección todo el camino, cableado DI su Pobre del hombre debería 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); 

Aviso cómo romper la cadena de dependencias menudo , asegurando que el número de dependencias para cada consumidor nunca llegue a ser demasiado grande.

En principio, esto significa que debe crear todas las dependencias en el momento del arranque, a menos que implemente un lazy loading strategy.

Cosas como la administración de tiempos de vida son exactamente el tipo de cosas en las que un Contenedor DI puede ser de gran ayuda, pero es completamente posible escribir una aplicación completa con solo following DI patterns and principles.

Con todo, aun así, recomendaría un Contenedor DI si es posible.

0

Puede hacer DI usando interfaces de contexto. No es difícil, y bastante directo.

Una interfaz de contexto es una clase que expone todas las vinculaciones de la configuración del módulo guice.

Este es un ejemplo de esto en el que asumo que AppPresenter + DashboardPresenter está en un paquete y necesita un "contexto", mientras que GadgetPresenter y GadgetConfigPresenter están en otro paquete y necesitan otro "contexto". La cantidad de contextos y cómo manejarlos depende completamente 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(); 
    } 
} 
Cuestiones relacionadas