2009-01-27 19 views
9

Estoy tratando de usar un contenedor IOC para crear el gráfico de objeto inicial dentro de mi aplicación.Tratando con dependencias circulares en IOC

Tengo un MainForm. Esta forma depende de un MenuStrip, que depende de múltiples MenuStripItems. Algunos MenuStripItems dependen de MainForm.

Por el momento configuro todas las dependencias para la inyección del constructor. Obviamente, la resolución de MainForm ahora da como resultado un desbordamiento de la pila, ya que las dependencias MenuStripItem de MainForm intentan resolver la forma principal, etc. etc ...

¿Cuál es la mejor manera de resolver esta dependencia circular?

+1

Tengo curiosidad por cómo manejó la referencia circular antes de involucrar el contenedor de IOC ... ¿Tiene una prueba de unidad que le da al formulario todas sus dependencias? – JasonTrue

+0

Antes de usar IOC, mi MainForm sería accesible globalmente con un Singleton. –

Respuesta

5

Las dependencias circulares son un signo de mal diseño, no importa si está utilizando IoC o no. Sugiero que hagas un rediseño para evitarlo. Agregar un objeto auxiliar puede ser una solución.

Por ejemplo, haga que los MenuStripItems dependan solo de una parte de MainForm que sea necesaria para ellos y no en su totalidad.

3

Realice una clase de controlador que proporcione los datos y la lógica que tanto MainForm como MenuStripItem necesitan para evitar la referencia circular.

3

Puede usar un setter para inyectar algunas de las dependencias después de la construcción.

1

No veo cómo la creación de una clase auxiliar o controlador resuelve el problema de dependencia circular.

Voy a dar algunos detalles más. Los elementos MenuStrip dependen de MainForm porque pueden establecer el contenido de MainForm. Siguiendo las sugerencias anteriores, digamos que creo una interfaz separada para el contenido de MainForm, IFormContent. MenuStripItem puede entonces depender de IFormContent. Pero una implementación de IFormContent volverá a depender de MainForm, lo que dará como resultado una dependencia circular.

¿Debería recurrir a la inyección setter en algún lugar en lugar de la inyección de constructor?

+1

Tiene una clase de controlador con una propiedad: Contenido. MenuStripItem establece la propiedad Content en el controlador y MainForm lo lee. Entonces, estas dos clases hacen referencia al controlador, pero el controlador no sabe nada sobre las dos clases de GUI. Entonces no hay referencia circular. –

0

¿Cómo se crean MenuStrip y MenuStripItems?

Cuando uso IOC, siempre existe una relación de 1 a 1 entre un servicio y las dependencias que el contenedor de IOC proporciona para el servicio. Si un servicio necesita más que uno o algo, entonces tendría una relación de 1 a 1 con un único objeto de fábrica que crea los elementos múltiples. Este método de fábrica podría parametrizarse para permitir que los elementos creados vuelvan a referirse a su contenedor.

3

Estoy de acuerdo con kgiannakakis:

dependencias circulares son un signo de mal diseño, no importa si está utilizando COI o no. Le sugiero que haga un rediseño para evitarlo. Agregar un objeto auxiliar puede ser una solución.

Para saber en qué métodos deben ser extraídos en la clase de ayuda, este proceso puede ayudar a:

Dado que tiene una clase A y de clase B que se hace referencia a la otra y crear una dependencia circular. Para averiguar qué métodos extraer en un objeto auxiliar externo, enumere todos los métodos en su clase A usados ​​por la clase A, y todos los métodos en su clase B utilizados por la clase A. La más corta de las dos listas es su oculto la clase C. ayudante

Inspirado por Miško Hevery http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-and-dependency-injection/

1

usted necesita crear un distribuidor clase (o interfaz) que contiene la referencia de ambas clases que esté usando. Debe utilizar esta clase del distribuidor (o interfaz) en lugar de cada clase de referencia que haya tratado de usar antes.

Explicando la solución:
Considerar 3 clases de la siguiente manera:

public Class A { 
    public Method CommonMethod(){ 
     //Some implementation... 
    } 

    Method C(){ 
     //CommonMethod form class B are using here 
     B obj = new B(); 
     B.CommonMethod(); 
    } 
} 


public Class B { 
    public Method CommonMethod(){ 
     //Some implementation... 
    } 

    Method D(){ 
     //CommonMethod form class A are using here 
     A obj = new A(); 
     A.CommonMethod(); 
    } 
} 


public Class DealerClass { 
    private readonly A _inctanceA; 
    private readonly B _inctanceB; 

    //Cunstructor method of the class 
    DealerClass(A inctanceA, B inctanceB){ 
     _inctanceA = inctanceA; 
     _inctanceB = inctanceB; 
    } 

    //Using CommonMethod of class A 
    public UsingCommonMethodA(){ 
     _inctanceA.CommonMethod(); 
    } 

    //Using CommonMethod of class B 
    public UsingCommonMethodB(){ 
     _inctanceB.CommonMethod(); 
    }  
} 

Así que de acuerdo a esta solución a utilizar métodos de otras clases que tienen dependencia circular entre sí en el DealerClass.

+0

parece más detallado. –

Cuestiones relacionadas