DI容器的好处和正确用法

时间:2015-06-24 19:52:50

标签: dependency-injection inversion-of-control ioc-container

我很难获得像Ninject,Unity或其他任何东西的IoC(DI)容器的优势。我理解如下概念:

  • DI:将依赖项注入需要它的类中(最好通过构造函数注入)。我完全明白为什么不那么紧密的耦合是一件好事。

    public MyClass{
        ISomeService svc;  
    
        public MyClass(ISomeService svc){
            svc = svc;
        }
    
        public doSomething(){
            svc.doSomething();
        }
    }
    
  • 服务定位器:当一个"容器"直接在需要依赖的类中使用,以解决依赖性。我确实认为这会产生另一种依赖性,我也看到基本上没有任何东西被注入。

    public MyClass{                 
        public MyClass(){}
    
        public doSomething(){
            ServiceLocator.resolve<ISomeService>().doSomething();
        }
    }
    

现在,令我困惑的是&#34; DI容器&#34;的概念。对我来说,它看起来就像一个服务定位器 - 据我所知 - 只应该在应用程序的入口点/启动方法中使用,以注册和解析依赖项并将它们注入到其他类的构造函数中 - 而不是在需要依赖的具体类中(可能出于同样的原因,为什么考虑服务定位器&#34;坏&#34;)

  • 当我可以创建依赖项并将其传递给构造函数时,使用容器的目的是什么?

    public void main(){                 
        DIContainer.register<ISomeService>(new SomeService());
        // ...
    
        var myclass = new MyClass(DIContainer.resolve<ISomeService>());
        myclass.doSomething();
    }
    
  • 将所有依赖项传递给应用程序初始化方法中的所有类是否真的有意义?最终可能需要(或不需要)100个依赖项,并且仅仅因为它被认为是一个很好的实践,您可以在init方法中创建它们吗?

1 个答案:

答案 0 :(得分:2)

  

当我可以创建依赖项并将其传递给构造函数时,使用容器的目的是什么?

DI容器应该可以帮助您快速创建对象图。您只需告诉它要用于哪些抽象(注册阶段)的具体实现,然后它就可以创建您想要的任何对象(解析阶段)。

如果您创建依赖项并将它们传递给构造函数(在应用程序初始化代码中),那么您实际上正在执行Pure DI

我认为Pure DI在许多情况下是更好的方法。请参阅我的文章here

  

将所有依赖项传递给应用程序初始化方法中的所有类是否真的有意义?最终可能需要100个依赖项(或者不需要),并且仅仅因为它被认为是一个很好的实践,你可以在init方法中创建它们吗?

我会说是的。您应该在应用程序启动时创建对象图。这称为composition root

如果您需要在应用程序启动后创建对象,则应使用factories(主要是抽象工厂)。这些工厂将与组合根中的其他对象一起创建。

您的类在构造函数中不应该做很多事情,这会使在组合根处创建所有依赖项的成本降低。

但是,我想说在特殊情况下使用new关键字创建某些类型的对象是可以的。就像对象是一个简单的Data Transfer Object (DTO)