我应该封装我的IoC容器吗?

7
我正在考虑是否值得花费额外的精力来封装我的IoC容器。经验告诉我,我应该在我的应用程序和任何第三方组件之间加入一层封装。但我不确定这是否有点过度。
我可以想到一些情况下,我可能想要切换容器。例如,我的当前容器停止维护,或者其他容器被证明更轻量级/高性能并更适合我的需求。如果发生这种情况,那么我可能需要重新连接很多东西。
需要明确的是,我正在考虑封装类型的注册和解析。我认为封装解析是一个易于实现的功能 - 我希望使用一个辅助/工具类来委托容器。
编辑:
假设我喜欢通过编程方式连接我的类型,以实现类型安全、编译时检查和可重构性。我正在寻找保护自己免受此代码及其对容器的依赖的影响的方法。
我还在为其他几个项目使用IoC容器,这些项目共享许多相同的关系,但是容器很难使用,所以我想进行更改。但是,更改意味着我失去了注册代码的可重用性。因此,我正在考虑封装。这不是一个巨大的负担,但我仍然希望减轻这种负担。
我想要:
- 最小化容器/容器版本更改的影响 - 在可能使用不同容器的项目之间提供某种级别的类型注册一致性 - 提供对我有意义的接口方法(例如RegisterSingleton而不是RegisterType(SomeLifetimeProvider) - 使用Unity作为示例)。 - 根据需要增强容器的条件/可扩展性,例如在解析/注册期间添加更好的缓存、日志记录等。 - 提供自己的模型来注册类型映射。
- 假设我想要在一个程序集/包中创建一堆RegistrationHandler对象,以便我可以轻松地将注册责任分离到多个类中,并自动获取这些处理程序而无需更改任何其他代码。
我意识到这有点主观,因此列出利弊可能会有所帮助。谢谢!

1
已经完成了。(至少是针对.NET。)Common Service Locator library 无论如何,我赞同Knesek先生的观点。通常您只需要在顶层类中依赖于容器。 - TrueWill
这似乎有点过头了,超出了我想要实现的目标。我只是想尽量减少变更对项目(当前或未来项目)的影响。我不想引入“另一个”第三方库来完成此操作。 - Ryan Emerle
在http://davybrion.com/blog/2009/11/integrating-your-ioc-container-with-agatha/中,实质上解决了与Agatha集成的IOC容器问题。 - Ruben Bartelink
4个回答

7

如果您确实需要更改IOC容器,请稍后再更改,仅在需要更改时才进行更改。

选择一种非侵入性的IOC容器。也就是说,连接到彼此的对象没有任何依赖于IOC容器。在这种情况下,没有什么需要封装的东西。

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

换句话说,让第一个IOC容器成为定义任何未来容器接口的容器,以便您不必发明自己的接口,并且可以将这种工作推迟到绝对需要它的时候。

修改:

我看不出有什么方法可以保证类型安全,除非:

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

类型解析通常是非侵入性的,这是它的本质;而注册通常需要大量特定于容器的代码。正是这些代码(假设我更喜欢类型安全而不是 XML 配置)我正在努力保护自己(和我的应用程序)免受其影响。我同意避开声明式类型映射是危险的(例如通过注释或属性)。 - Ryan Emerle
此外,我对当前任何一个IoC容器的接口都不是完全满意,因此我不知道我是否想要选择的那个。 - Ryan Emerle
1
@Ryan:虽然我同意类型安全性胜过XML,但你会发现你有一个类(甚至可能只有一个方法)来执行给定项目的所有注册。根据您拥有的项目数量,抽象注册可能提供很少的好处。 - TrueWill

1

没问题,就这么做吧。这并不需要太多额外的努力,而且正如你所说,它可以更好地隔离第三方组件。

这也意味着,如果你找到了更好的IoC容器,你可以很容易地切换。我最近就用structuremap替换了Spring.net IoC容器。

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


1

最佳实践是仅在实际需要时执行某些操作,永远不要编写您猜测未来可能需要的代码(这就是所谓的 YAGNI 原则)。如果您的架构正确,可以轻松更改容器,如果实际上确实有必要...

如果您认为需要这种灵活性,可以查看 CodePlex 上的 Common Service Locator 项目。它正是您寻找的:为各种 IoC 容器提供公共外观。

希望对您有所帮助!


有时候,您需要对未来应用程序的维护需求做出有根据的猜测。虽然我完全遵循YAGNI原则,但我更喜欢具有一定程度的未来支持能力。一个单一、可重用的封装库(以及相关的测试)所需的工作量非常小,现在考虑这个选项是值得的。 - Ryan Emerle
1
我和Thomas(还有Doug)在一起 - 现在看起来只是最小的努力。这将增加更多的代码进行测试,更多可能会出错的代码以及更多需要维护的代码。而为了什么?为了在可能永远不会发生的事情上节省你一点时间。我甚至会说很可能永远不会发生,因为您更改容器的原因(例如,从属性驱动的注入转换为声明性映射)是那些不会被封装接口覆盖的事情。 - Jeff Sternal
1
只是出于好奇:哪种应用程序需要将“更改IoC容器实现”作为维护需求?顺便说一下:如果现在封装容器需要“最小的努力”,那么将来更改它时需要的努力甚至会更少,如果这个需求真正存在的话... - Thomas Weller

1

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

在我看来,许多了解IOC容器的代码是一种反模式,会增加复杂性。我见过很多对象自由地向IOC容器请求它们的依赖项,然后它们基本上将IOC容器降级为高维护的服务定位器。

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接