【问题标题】:Should I encapsulate my IoC container?我应该封装我的 IoC 容器吗?
【发布时间】:2010-12-18 03:25:33
【问题描述】:

我正在尝试确定是否需要付出额外的努力来封装我的 IoC 容器。经验告诉我,我应该在我的应用程序和任何第三方组件之间放置一层封装。我只是不知道这是否有点矫枉过正。

我可以想到我可能想要切换容器的情况。例如,我当前的容器停止维护,或者其他容器被证明更轻/性能更佳,更适合我的需求。如果发生这种情况,那么我可能需要重新布线。

为了清楚起见,我正在考虑封装类型的注册解析。我认为封装分辨率是不费吹灰之力的 - 我希望将帮助程序/实用程序类委托给容器是一种常见的做法。

编辑:

假设我更喜欢以编程方式连接我的类型以实现类型安全、编译时检查和可重构性。这是这个代码及其对容器的依赖,我希望保护自己免受攻击。

我还为其他几个共享许多相同关系的项目使用了 IoC 容器,但使用该容器很痛苦,所以我想要改变。但是,更改意味着我失去了注册码的可重用性。因此,为什么我正在考虑封装。这不是一个巨大的负担,但我还是想减轻这个负担。

我正在寻找:

  • 尽量减少容器/容器版本变化的影响
  • 为可能使用不同容器的项目提供一定程度的类型注册一致性
  • 提供对我有意义的接口方法(RegisterSingleton 而不是 RegisterType( SomeLifetimeProvider ) - 以 Unity 为例)。
  • 随着条件/可扩展性要求的变化(例如在解析/注册期间添加更好的缓存、日志记录等。
  • 提供我自己的模型来注册类型映射。
    • 假设我想在一个程序集/包中创建一堆 RegistrationHandler 对象,这样我就可以轻松地将注册职责分离到多个类中,并自动获取这些处理程序,而无需在其他任何地方更改代码。

我意识到这有点主观,所以利弊可能会有所帮助

谢谢!

【问题讨论】:

  • 已经完成了。 (至少对于 .NET。)Common Service Locator library 无论如何,我同意 Knesek 先生的观点。你通常只需要在你的顶级类中依赖你的容器。
  • 对于我想要实现的目标来说,这似乎有点矫枉过正。如果我选择更改容器(在我当前的项目或未来的项目中),我只想尽量减少更改的影响。我不想引入另一个第三方库来完成这个。

标签: ioc-container encapsulation


【解决方案1】:

是的,去吧。这不是很多额外的努力,就像你说的那样,它可以让你更好地与第三方组件隔离。

这也意味着,如果您发现更好的东西,您可以轻松切换 IoC 容器。我最近通过将 Spring.net IoC 容器换成结构映射来做到这一点。

codeplex 上的ASP.NET MVC Contrib 项目是一个很好的起点。这是我实现的基础。

【讨论】:

    【解决方案2】:

    稍后再做,并且仅当您确实需要更改 IOC 容器时。

    选择一个非侵入性的 IOC 容器。也就是说,相互连接的对象对 IOC 容器没有任何依赖关系。在这种情况下,没有什么可以封装的。

    如果您必须选择一个要求您对该容器具有依赖项的 IOC 容器,请选择一个具有最简单的依赖项/API 的容器。如果您需要替换此 IOC 容器(您可能不会),请实现将新 API 连接到旧 API 的适配器。

    换句话说,让第一个 IOC 容器定义任何未来容器的接口,这样您就不必发明自己的容器,并且您可以延迟任何此类容器工作,直到你绝对需要它。

    编辑:

    我没有看到任何一种保证类型安全的方法:

    1. 设计一个相对复杂的 Builder 模式实现以及将编写 IOC 配置文件或等效文件的访问者实现。
    2. 实现类型安全的 IOC 配置 DSL。 (如果我有多个需要可交换 IOC 容器的应用程序,我会选择。)

    【讨论】:

    • 类型解析本质上通常是非侵入性的;注册通常需要大量特定于容器的代码。这是我试图保护自己(和我的应用程序)的代码(假设我更喜欢类型安全而不是 XML 配置)我同意避开声明性类型映射是危险的(例如通过注释或属性) .
    • 此外,我对当前 IoC 容器的任何接口并不完全满意,所以我不知道我想要我选择的那个。
    • @Ryan:虽然我同意 XML 的类型安全性,但我认为您会发现您有一个类(甚至可能是一种方法)可以执行给定项目的所有注册。根据您拥有的项目数量,抽象注册可能没有什么好处。
    【解决方案3】:

    最好的做法是仅在实际需要时才做某事,并且永远不要编写您认为将来有时会需要的东西(这就是所谓的YAGNI-原则)。如果你的架构没问题,你可以很容易地改变容器,如果它真的有必要的话......

    如果您认为自己需要这种灵活性,您可以查看 CodePlex 的 Common Service Locator project。它完全符合您的要求:为各种 IoC 容器提供通用外观。

    HTH!

    【讨论】:

    • 有时您需要对应用程序未来的维护需求做出有根据的猜测。尽管我全心全意地遵循 YAGNI 原则,但我更喜欢有一定程度的面向未来的能力。一个单一的、可重用的封装库(和相关的测试)只需要很少的努力,现在值得考虑。
    • 我和 Thomas(和 Doug)在一起 - 现在只是 似乎 需要很少的努力。它将添加更多代码进行测试、更多可能破坏的代码以及更多需要维护的代码。为了什么?为您节省一点时间来处理可能永远不会发生的事情。我什至会说可能永远不会发生,因为您要更改容器的类型(例如,从属性驱动注入到声明性映射)就是这样的类型这不会被封装接口覆盖。
    • 只是出于好奇:什么样的应用程序会将“更改 IoC 容器实现”作为维护需求?顺便说一句:如果现在封装容器需要“最少的努力”,那么将来改变它需要更少的努力,如果这种需要真的出现......
    【解决方案4】:

    比起封装 IOC 容器本身,我更喜欢隔离与 IOC 容器交互的轨迹。例如,在 ASP.Net MVC 中,我通常将容器暴露在控制器工厂和 global.aspx.cs 文件中,通常是在其中设置。

    在我看来,拥有大量了解 IOC 容器的代码是一种增加复杂性的反模式。我见过相当多的代码,其中对象可以随意向 IOC 容器询问它们的依赖关系,然后他们基本上将 IOC 容器简化为一个高维护的服务定位器。

    由于 IOC 容器可以将依赖关系解析到任意深度,因此很容易使控制器工厂成为负责控制容器反转的组件。每个控制器的构造函数本质上指定了它需要的服务/存储库/网关。

    对于我的任何应用程序,交换 IOC 容器本质上是重写配置容器的代码(指定绑定等)并连接控制器工厂的问题。对于作为服务公开的应用程序,相同的基本思想应该是可合理管理的,但根据运行时的限制,您可能必须使用 setter 注入而不是构造函数注入。

    【讨论】:

      猜你喜欢
      • 2019-06-04
      • 2013-03-29
      • 2011-01-25
      • 1970-01-01
      • 1970-01-01
      • 2015-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多