register pattern objects locator ioc injection informatica framework fowler dependency control design-patterns inversion-of-control

design patterns - pattern - Tratando con dependencias circulares en IOC



service locator vs dependency injection (7)

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

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?


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


Las dependencias circulares son un signo de mal diseño, no importa si usa 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.


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

Daré algunos detalles más. MenuStripItems depende 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.

¿Quizás debería recurrir a la inyección setter en algún lugar en lugar de la inyección del constructor?


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


¿Cómo se crean MenuStrip y MenuStripItems?

Cuando uso IOC, siempre hay una relación de 1 a 1 entre un servicio y las dependencias que proporciona el contenedor de IOC 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.


Estoy de acuerdo con kgiannakakis:

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

Para descubrir qué métodos se deben extraer en la clase auxiliar, este proceso puede ayudar:

Dado que tiene una clase A y una Clase B que hacen referencia entre sí y crean 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 ayudante oculto clase C.

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


Necesita crear una clase de distribuidor (o interfaz) que contenga la referencia de las dos clases que los está utilizando. Debería utilizar esta clase de distribuidor (o interfaz) en lugar de cada clase de referencia que haya tratado de usar antes.

Explicando la solución:
Considera 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(); } }

De acuerdo con esta solución, debe usar métodos de otras clases que tengan dependencia circular entre sí en DealerClass .