依赖注入与服务位置

Law*_*eld 37 c# singleton dependency-injection dependency-management service-locator

我目前正在权衡DI和SL之间的优缺点.但是,我发现自己处于以下问题22中,这意味着我应该只使用SL作为一切,并且只在每个类中注入一个IoC容器.

DI Catch 22:

一些依赖项,如Log4Net,根本不适合DI.我称之为元依赖关系并认为它们对调用代码应该是不透明的.我的理由是,如果一个简单的类'D'最初是在没有记录的情况下实现的,然后增长到需要记录,那么依赖类'A','B'和'C'现在必须以某种方式获得这种依赖并将其从'A'到'D'(假设'A'组成'B','B'组成'C',依此类推).我们现在已经进行了重要的代码更改,因为我们需要登录一个类.

因此,我们需要一种不透明的机制来获取元依赖性.我想到了两个:Singleton和SL.前者具有已知的局限性,主要是关于刚性范围的能力:最好的是Singleton将使用存储在应用程序范围内的抽象工厂(即在静态变量中).这允许一些灵活性,但并不完美.

更好的解决方案是将IoC容器注入此类,然后使用该类中的SL从容器中解析这些元依赖关系.

因此,捕获22:因为类现在正在注入IoC容器,那么为什么不使用它来解析所有其他依赖项呢?

我非常感谢你的想法:)

jas*_*son 59

因为该类现在正在注入IoC容器,那么为什么不使用它来解析所有其他依赖项呢?

使用服务定位器模式完全打败了依赖注入的一个主要点.依赖注入的关键是使依赖关系显式化.一旦你通过不在构造函数中使它们成为显式参数来隐藏这些依赖项,就不再需要完全成熟的依赖注入了.

这些都是名为Foo(设置为Johnny Cash歌曲主题)的类的构造函数:

错误:

public Foo() {
    this.bar = new Bar();
}
Run Code Online (Sandbox Code Playgroud)

错误:

public Foo() {
    this.bar = ServiceLocator.Resolve<Bar>();
}
Run Code Online (Sandbox Code Playgroud)

错误:

public Foo(ServiceLocator locator) {
    this.bar = locator.Resolve<Bar>();
}
Run Code Online (Sandbox Code Playgroud)

对:

public Foo(Bar bar) {
    this.bar = bar;
}
Run Code Online (Sandbox Code Playgroud)

只有后者才会依赖于Bar显式.

对于日志记录,有一种正确的方法可以实现它,而不会渗透到您的域代码中(它不应该,但如果确实如此,则使用依赖注入时段).令人惊讶的是,IoC容器可以帮助解决这个问题.从这里开始.

  • @Lawrence Wagerfield:我不同意.请以正确的方式查看我的编辑以处理日志记录.注射它们,或使用AOP方法. (5认同)

dev*_*tal 8

服务定位器是一种反模式,其原因在http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx中有详细描述.在日志记录方面,您可以像其他任何一样将其视为依赖项,并通过构造函数或属性注入注入抽象.

与log4net唯一的区别是它需要使用该服务的调用者类型. 使用Ninject(或其他一些容器)如何找出请求服务的类型?描述了如何解决这个问题(它使用Ninject,但适用于任何IoC容器).

或者,您可以将日志记录视为一个交叉问题,这不适合与业务逻辑代码混合使用,在这种情况下,您可以使用由许多IoC容器提供的拦截. http://msdn.microsoft.com/en-us/library/ff647107.aspx描述了使用Unity进行拦截.

  • 服务地点不是反模式.它只是一种经常使用不当的模式.目的是基于可变数据的运行时间分辨率.如果您可以在构造函数时访问该信息,则可能不希望直接使用定位器. (4认同)

小智 5

我的意见是,这取决于.有时一个更好,有时另一个.但我会说通常我更喜欢DI.原因很少.

  1. 当以某种方式将依赖注入组件时,它可以被视为其接口的一部分.因此,组件的用户更容易提供这种依赖,因为它们是可见的.在注入SL或静态SL的情况下,隐藏了依赖关系并且组件的使用有点困难.

  2. 注入的依赖对于单元测试更好,因为您可以简单地模拟它们.在SL的情况下,您必须再次设置Locator + mock依赖项.所以这是更多的工作.