【问题标题】:Dealing with circular dependencies in IOC处理 IOC 中的循环依赖
【发布时间】:2009-01-27 07:44:42
【问题描述】:

我正在尝试使用 IOC 容器在我的应用程序中创建初始对象图。

我有一个主窗体。此表单依赖于一个 MenuStrip,该 MenuStrip 依赖于多个 MenuStripItem。一些 MenuStripItems 依赖于 MainForm。

目前我为构造函数注入设置了所有依赖项。显然,现在解析 MainForm 会导致堆栈溢出,因为 MainForm 的 MenuStripItem 依赖项会尝试解析 Mainform 等...

解决这种循环依赖的最佳方法是什么?

【问题讨论】:

  • 我很好奇您在涉及 IOC 容器之前如何处理循环引用...您是否有一个单元测试来处理表单的所有依赖项?
  • 在使用 IOC 之前,我的 MainForm 可以使用 Singleton 全局访问。
  • 循环依赖的一些参考:stackoverflow.com/a/37445480/1371329

标签: design-patterns inversion-of-control


【解决方案1】:

无论您是否使用 IoC,循环依赖都是糟糕设计的标志。我建议您重新设计以避免它。添加辅助对象可能是一种解决方案。

例如,使 MenuStripItems 仅依赖于 MainForm 的一部分,而不是全部。

【讨论】:

    【解决方案2】:

    创建一个控制器类,提供 MainForm 和 MenuStripItem 都需要避免循环引用的数据和逻辑。

    【讨论】:

      【解决方案3】:

      您可以在构造后使用 setter 注入一些依赖项。

      【讨论】:

        【解决方案4】:

        我同意kgiannakakis:

        循环依赖是 糟糕的设计,无论您是否使用 国际奥委会与否。我建议你做一个 重新设计以避免它。添加助手 对象可能是一个解决方案。

        要找出应该将哪些方法提取到辅助类中,这个过程可能会有所帮助:

        假设您有一个 A 类和一个 B 类,它们相互引用并创建循环依赖。 要找出要提取到外部帮助器对象中的方法,请列出类 A 使用的类 A 中的所有方法,以及类 A 使用的类 B 中的所有方法。两个列表中较短的是隐藏的帮助器C类。

        灵感来自 Miško Hevery http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-and-dependency-injection/

        【讨论】:

          【解决方案5】:

          您需要创建一个 dealer 类(或接口),其中包含您正在使用的两个类的引用。您应该使用这个 dealer 类(或接口),而不是您之前尝试使用的每个引用类。

          解释解决方案:
          考虑以下 3 个类:

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

          因此,根据此解决方案,您应该在 DealerClass 中使用彼此具有循环依赖关系的其他类的方法。

          【讨论】:

          • 好像比较详细。
          【解决方案6】:

          我看不出创建帮助类或控制器如何解决循环依赖问题。

          我会提供更多细节。 MenuStripItems 依赖于 MainForm,因为它们可以设置 MainForm 的内容。按照上述建议,假设我为 MainForm 内容 IFormContent 创建了一个单独的接口。 然后 MenuStripItem 可以依赖于 IFormContent。 但是 IFormContent 的实现将再次依赖于 MainForm,从而导致循环依赖。

          也许我应该在某个地方使用 setter 注入而不是构造函数注入?

          【讨论】:

          • 您有一个具有一个属性的控制器类:内容。 MenuStripItem 在控制器上设置 Content 属性,MainForm 读取它。所以这两个类引用了控制器,但是控制器对这两个 GUI 类一无所知。所以没有循环引用。
          【解决方案7】:

          MenuStrip 和 MenuStripItems 是如何创建的?

          当我使用 IOC 时,服务与 IOC 容器为服务提供的依赖项之间始终存在一对一的关系。如果一项服务需要不止一项,那么它将与创建多个项目的单个工厂对象建立一对一的关系。这个工厂方法可以被参数化以允许创建的项目引用回它们的容器。

          【讨论】:

            猜你喜欢
            • 2011-07-26
            • 2015-07-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-09-22
            • 2013-08-21
            • 2012-06-07
            相关资源
            最近更新 更多