我们有一个大型解决方案(> 100个项目),几乎每种类型都使用服务定位器(示例1)或我们自己的类型字典(示例2)进行实例化。
例如我们有:
IQuote quote = Registry.Resolve<IQuote>();
或
IQuote quote = Registry.Find<IQuote>(args);
第二个示例转到配置文件,找到使用反射实例化的具体对象。
通过代码跟踪时会让生活变得更加困难 - 因为不清楚使用的是什么具体类型 - 因此我们必须多次检查映射,因为我们正在尝试学习代码的一部分。使用以上作为示例按F12:quote.DoSomething()
将转到界面定义。
实现起来也有点困难 - 我们需要一个接口+具体的类+配置映射,当替代只有一个类时。
来想一想 - 我不知道有什么东西曾被“换掉”换成另一种类型 - 所以尽管我们已经实现了IoC,但我们还没有使用过它,或者至少没有用过它。
所以 - 它真的值得吗?我们是否错误/太多地实施了它?我误解了什么吗?
答案 0 :(得分:4)
在我看来,你不需要考虑到DI,每个班级都要工作。我会使用以下策略:
模块应该是相对细粒度的。
在一些常见的地方你需要使用DI,通常它是可替换的数据源和(不经常)算法。使用常识来检查某些东西是否需要更换。如果你发现某些东西需要DI或者受到影响,请不要犹豫,尽早进行重构。
答案 1 :(得分:4)
你们正在使用的是服务定位器,它被视为反模式, 因为:
http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx
答案 2 :(得分:2)
你展示的不是依赖注入,它是一个可配置的注册表(它也是一种模式,但却完全不同)。所以,是的,看起来是一个坏主意和一种误解。
为了能够从某些设计模式中获益,您必须先了解其中的好处。如果你不了解它们,那么你可能不应该打扰。
答案 3 :(得分:1)
如果你进行单元测试,某种类型的依赖注入对于存根或模拟依赖性是必不可少的。 (单元测试不应该依赖于文件系统,数据库,网络等依赖项。)
答案 4 :(得分:0)
我认为你使用DI容器混淆了更一般的依赖注入概念,这是实现非常灵活的DI形式的一种手段。 Here是一篇很好的文章,将DI解释为一个概念。
在你的场景中,在我看来你可以摆脱DI容器,但是如果只是为了可测试性,可能仍然想要保留某种形式的DI(正如其他人已经指出的那样)。一种常见的实现模式是实现“广泛”构造函数,通过这些构造函数可以注入依赖 ,并在单元测试中使用。此外,还将有“更窄”的构造函数,它将实例化具体类并将它们传递给“宽泛”构造函数。这些可以在生产代码中使用,直到需要实际交换依赖关系。
class MyClass
{
// This will be called from production code
public MyClass() : this(new Foo(), new Bar())
{}
// This will be called from tests and can be used in production code if needed
public MyClass(IFoo foo, IBar bar)
{
//do whatever you want to do in the ctor here
}
}