依赖可注射性是依赖注入的唯一理由吗?

fea*_*net 14 c# dependencies unit-testing design-patterns dependency-injection

据我所知,DI的优点是:

  • 减少依赖性
  • 更多可重用代码
  • 更可测试的代码
  • 更易读的代码

假设我有一个存储库OrderRepository,它充当通过Linq到Sql dbml生成的Order对象的存储库.我无法使我的订单存储库通用,因为它执行Linq Order实体和我自己的Order POCO域类之间的映射.

由于OrderRepository必然依赖于特定的Linq to Sql DataContext,因此无法真正说明DataContext的参数传递使代码可重用或以任何有意义的方式减少依赖性.

它还使代码更难阅读,以实例化我现在需要编写的存储库

new OrdersRepository(new MyLinqDataContext())

另外与存储库的主要目的相反,即抽象/隐藏DataContext的存在以消耗代码.

所以一般来说我认为这将是一个非常可怕的设计,但它会带来便利单元测试的好处.这有充分的理由吗?还是有第三种方式?我对听取意见非常感兴趣.

Rob*_*Rob 12

依赖注入的主要优点是测试.当我第一次开始采用测试驱动开发和DI时,你已经找到了一些对我来说很奇怪的东西.DI确实破坏了封装.单元测试应测试与实现相关的决策; 因此,您最终会暴露出纯粹封装的场景中不会出现的细节.您的示例很好,如果您没有进行测试驱动开发,您可能希望封装数据上下文.

但是你说的,因为OrderRepository必然依赖于特定的Linq到Sql DataContext,我不同意 - 我们有相同的设置,只依赖于接口.你必须打破这种依赖.

然而,让您的示例更进一步,如何在不运行数据库的情况下测试您的存储库(或其客户端)?这是单元测试的核心原则之一 - 您必须能够在与外部系统交互的情况下测试功能.没有比数据库更重要的了.依赖注入是一种模式,可以打破子系统和层的依赖关系.没有它,单元测试最终需要大量的夹具设置,变得难以编写,易碎且太慢.结果 - 你不会写它们.

让你的榜样更进一步,你可能会

在单元测试中:

// From your example...

new OrdersRepository(new InMemoryDataContext());

// or...

IOrdersRepository repo = new InMemoryDataContext().OrdersRepository;
Run Code Online (Sandbox Code Playgroud)

和生产中(使用IOC容器):

// usually...

Container.Create<IDataContext>().OrdersRepository

// but can be...

Container.Create<IOrdersRepository>();
Run Code Online (Sandbox Code Playgroud)

(如果你没有使用过IOC容器,它们就是使DI工作的粘合剂.把它想象成对象图的"make"(或ant)......容器为你构建依赖图并完成所有的繁重的施工).在使用IOC容器时,您将获得在OP中提到的依赖项隐藏.依赖关系由容器配置和处理,作为一个单独的关注点 - 调用代码可以只询问接口的实例.

这本书非常出色,详细探讨了这些问题.查看由Mezaros提供的xUnit测试模式:重构测试代码.这是将您的软件开发能力提升到新水平的书籍之一.

  • DI的主要优点是解耦.来自http://en.wikipedia.org/wiki/Dependency_inversion_principle的引文:"依赖性倒置原则的目标是将高级组件与低级组件分离,以便可以使用不同的低级组件实现进行重用." (2认同)
  • @fearofawhacplanet on usefuless(why):你打破了依赖性,这样你就可以在不需要数据库的情况下对DataContext进行单元测试.如果那不是目标,我同意在你的场景中使用DI是不值得的. (2认同)