【问题标题】:Why doesn't Simple Injector have an IContainer abstraction like Unity?为什么 Simple Injector 没有像 Unity 这样的 IContainer 抽象?
【发布时间】:2013-04-25 22:23:24
【问题描述】:

我在上一个项目中使用了 Unity,总体上很满意。但是基准测试让我认为我可以在下一个项目中使用 Simple Injector。

然而,Simple Injector 似乎没有Container 类的接口。这意味着每当我想在方法中使用容器时,我都无法模拟容器进行单元测试。

我很困惑,一个真正基于接口运行的工具,它本身如何不会成为容器的接口。我知道依赖注入的经典方法除了启动之外不需要容器。 (其余的使用构造函数注入。)但是我发现当橡胶撞到路时,这并不总是正确的。有时您只需要容器就可以在代码中进行“解析”。

如果我使用 Simple Injector,那么该代码似乎更难进行单元测试。

我说的对吗?还是我错过了什么?

【问题讨论】:

  • 为什么不用抽象工厂代替注入容器?

标签: dependency-injection inversion-of-control unity-container simple-injector


【解决方案1】:

Simple Injector 不包含IContainer 抽象,因为:

  • Simple Injector 定义它是没有用的, 因为在依赖IContainer 而不是Container 的情况下,您的代码在这种情况下仍将依赖于Simple Injector,这会导致供应商锁定,即Simple Injector tries to prevent

  • 除了应用程序的Composition Root 之外,您编写的任何代码都不应依赖于容器,也不应依赖于对容器的抽象。两者都是Service Locator anti-pattern 的实现。

  • 在单元测试时不应该使用 DI 库。在进行单元测试时,您应该在被测类中手动注入所有假对象或模拟对象。使用容器只会使事情复杂化。也许您正在使用容器,因为手动创建这些类对您来说太麻烦了。这可能表明您的代码(您可能违反了Single Responsibility Principle)或您的测试(您可能缺少factory method to create the class under test)存在问题。

  • 您可以使用容器进行集成测试,但您 首先不应该有那么多集成测试。重点应该放在单元测试上,这在应用依赖注入模式时应该很容易。最重要的是,与依赖非常广泛的库定义的接口相比,有更好的方法可以从集成测试中隐藏容器。

  • 自己定义这样的接口(加上一个适配器)是微不足道的,这证明在库中没有它是合理的。正如Dependency Inversion Principle 所述,为您的应用程序定义正确的抽象是您作为应用程序开发人员的工作。倾向于这样做的库和框架大部分时间都无法提供适用于所有人的抽象。

  • 库本身不使用该抽象,根据Framework Design Guidelines,库应该在这种情况下不为您定义此类抽象。如上一点所述,Simple Injector 无论如何都会弄错抽象。

  • 最后但同样重要的是,Simple Injector 容器确实实现了 System.IServiceProvider,它在 mscorlib.dll 中定义并可用于检索服务对象。

【讨论】:

  • 我不想在我的测试中使用容器。我想对使用容器的方法进行单元测试。在这种情况下,我无法模拟容器以不使用完整的 SimpleInjector 逻辑。
  • 但是为什么那个类对容器有依赖呢?具有(足够)逻辑进行测试的类不应直接依赖于容器。只有基础设施组件(作为组合根的一部分)才应该依赖于容器或容器的抽象。您显然无法测试您的系统,因为您违反了这条规则。
  • 如果你注入容器来“限制参数的数量”,这可能意味着这个类做的太多了;违反单一职责原则。请重新考虑您的策略。我热衷于打击这种对容器的滥用。如果您有疑问,请发布一些在 SO 上获取容器注入 herr 的类的真实示例,或直接给我发邮件。我很乐意向您解释如何更改设计以使问题消失。
  • 参数都是由于单一职责问题。我有一个 IPatientService、IDoctorService、IConfigService、IRegionAdapter、IRequistionHelpService、ISearchService 等等。如果我有一个 UI 需要所有这些,那么我最终会得到很多构造函数参数。坦率地说,我不介意。但我的一些团队成员对此表示不满。
  • 该 UI 显然违反了 SRP,这将导致可维护性问题,但名称为 *Service、*Manager、*Helper 等的类也是如此。我们称它们为 God Classes。您的应用程序可能会受益于不同的设计。查看this articlethis article,了解如何改进应用程序的设计。
【解决方案2】:

我认为这里给出的答案完全建立在接受 ServiceLocator 是一种反模式的基础上,而我不认为这在全球范围内被认为是正确的。请参阅 Windows Workflow Foundation 的扩展支持。

反模式链接(及其两个更新)也可能很弱......最新更新声称违反封装(“减轻您必须了解代码中每段代码的每个实现细节的负担基础。”),同时声称对于该声明的依赖关系的前期知识与通过单元测试发现它们在某种程度上有所不同。无论哪种方式,您都需要知道该给它什么。

总而言之,如果你想遵循 Locator 模式,要么利用它的 IServiceProvider,要么简化你的容器填充(到单例)并为其创建一个静态包装器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 2014-07-12
    • 2014-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多