一般来说,我的依赖项被抽象为接口,但我只会在非测试使用期间使用一个具体的实现。例如,我是否要撰写FooService
:
public class FooService : IFooService
{
private readonly IBarDependency _barDependency;
public FooService(IBarDependency barDependency)
{
this._barDependency = barDependency;
}
public FooService() : this (new BarDependency())
{
// nothing to do here
}
. . . // code goes here
}
现在纯粹主义者倾向于惊恐万分,因为我在无参数构造函数中实例化了一个具体的类。在过去,我已经耸耸肩了,因为我知道我唯一不会使用具体类的时候是单元测试和模拟依赖项。
虽然它将FooService
类与BarDependency
类耦合,但它不是紧耦合;这些类和接口也存在于同一个程序集中,所以在我看来,我不会在这里丢失很多东西,或者把自己画成一个角落。我仍然可以轻松地测试FooService
类而不会获得无法管理的代码,只需使用允许我传入模拟接口的构造函数。
所以问题是:这里的实际风险是什么?我在这种值得添加IoC容器的模式中失去了什么?
答案 0 :(得分:6)
例如,终身管理。也许您在整个代码中使用BarDependency
并且只希望一个实例存活。如果每个用户都创建自己的实例,则无法执行此操作。
如果您想要将new BarDependency()
替换为new NewBarDependency()
,还必须找到{{1}}的所有用法。
容器为您修复了这两个问题,然后在一个方法中配置对象的实例化和生命周期,即设置容器的位置。
答案 1 :(得分:2)
这取决于,但如果其他开发人员需要访问FooService,则基本上会隐藏对BarDependency的依赖。在我看来,不仅模拟和测试是使用依赖注入的原因,而且还清楚地表明了注册类使用的内容,以及它们需要正常工作的内容。 也许我会更加纯粹主义,但是当这样的模式还可以,那么很容易进一步完成并最终得到一个完全紧密耦合且硬的可维护代码。
答案 2 :(得分:1)
在没有依赖注入的情况下,您失去的是能够集中依赖关系管理的所有方面。当您将所有信息放在一个地方时,可视化依赖关系图并管理对象的生命周期,而不是分散在整个代码中。
一个具体的例子是,如果你想要替换某些类中使用的IBarDependency
的默认实现,而不是所有类。如果依赖关系全部连接在同一个文件或文件组中,那么推理哪些替换要容易得多。