关于DI,IoC和服务定位器的困惑

时间:2013-10-08 07:27:00

标签: c# dependency-injection inversion-of-control service-locator

我已经阅读过有关IoC,DIP,DI和服务定位器的各种文章,但我有点困惑,因为有些文章的例子太模糊,而其他一些文章只有一些具体的例子而没有提及其他案例。

请您帮我解决一下这个问题,查看下面的示例并简要说明哪些示例符合哪种模式?

  • 手动将接口传递给构造函数:

    class Consumer
    {
      public Consumer(IStore store){...}
    }
    ...
    
    Consumer c = new Consumer(new ConcreteStore());
    
  • 与第一个示例相同,但使用了第三方库(Unity,Windsor,Ninject)

  • 与第一个示例相同,但使用BaseStore类而不是IStore接口

  • 将依赖项传递给其他方法,而不是构造函数:

    class Consumer
    {
      public BySomething(IStore store){...}
    }
    ...
    
    Consumer c = new Consumer();
    c.BySomething(new ConcreteStore());
    
  • 传递依赖关系掩盖在其他界面内部(此解决方案的奖励 - 当“世界”中发明了一些其他东西而消费者希望使用它们时,我们不必更改构造函数参数而只是更新IWorld;我们可以在测试时用其他东西完全取代整个世界:

    interface IWorld
    {
      IDictionary<string,IStore> Stores { get; set; }
      IDictionary<string,ICityMap> Maps { get; set; }
      ...
    }
    
    class Consumer
    {
      public Consumer(IWorld world){...}
      public BySomething(string store, string city){...}
    }
    
    ...
    
    IWorld myWorld = new HeavenlyWorld();
    ... // adding stores, maps and whatnot
    
    Consumer c = new Consumer(myWorld);
    

    一个子问题:在这种情况下,IWorld是服务定位器还是不完全?

  • 传递回调函数或委托(在本例中为.NET Action):

    c.BySomething(store, city, new Action(() => {...} ));
    

    我添加了这个案例,因为文章Inversion of Control声明每个回调都是IoC。这是真的吗?

2 个答案:

答案 0 :(得分:2)

您列出的所有内容都是依赖注入的一种形式。

  1. “穷人的”DI
  2. DI使用IoC容器
  3. “穷人的”DI再次。无论您使用的是接口还是抽象类,DI都可以工作。
  4. 方法注入
  5. 我不确定你在这里问什么。听起来你想在运行时更改IWorld的实例,这可能是Property Injection而不是Constructor Injection的情况。属性常常用于可选依赖项或可以更改的属性。您是否在运行时使用服务定位器或其他方式设置该依赖关系取决于您。另一件需要考虑的事情是IWorld可能只依赖于上下文,在这种情况下,您可以执行上下文隐式构造函数注入,其详细信息超出了此问题的范围。
  6. 与DI
  7. 无关

答案 1 :(得分:1)

每次将依赖项作为构造函数/方法参数传递时,都是Dependecy Injection。它可以是手动的,就像在大多数示例中一样,或者自动使用DI Container也称为IoC容器。

使用容器意味着使用deps的对象由容器构造。您可以直接向容器询问该服务,在这种情况下,有一个静态属性或方法(在asp.net mvc中认为DependecyResolver)公开该服务。在这种情况下,您正在使用服务定位器模式。 IWork 在您的示例中不是定位器,它只是一个依赖项。

要继续使用依赖项解析程序示例,请将所有相关类型注册到容器中,然后将容器构建为依赖项解析程序。然后asp.net mvc框架使用解析器(服务定位器 - SL)来实例化控制器,视图和所需的所有deps。

使用SL模式可以作为框架的一部分,但是如果你在应用程序中使用它来实例化对象,那就不行了,因为它将代码耦合到定位器。有时是唯一的解决方案,但99%你只是一个反模式。