害怕使用依赖注入框架

时间:2009-08-24 23:57:12

标签: design-patterns dependency-injection service-locator

我一直在阅读依赖注入框架。我真的爱上了将问题分开并让对象完成核心工作的想法 - 这无疑是一个优秀且长期存在的设计原则!

然而,我对DI框架的阅读越多,我就越担心: 1)他们“自动”解决依赖关系的方式 2)关于配置文件中引入的极端复杂性

就第2点而言,我看到我的客户花费了数百万美元来培训产品上的人,其中重要的部分是如何“不”触摸配置文件。管理员现在担心这些配置文件。

然而,我看到另一种称为服务定位器的模式,我可以很好地在应用程序开始时组装我想要的所有“全局”服务(可能是应用程序主机或应用程序上下文或其他)。让这个服务定位器全球可用,瞧!

但是,当我根据某些标准(已知谁?)需要多种类型的“全球”服务时,我发现使用服务定位器方法时灵活性会降低!

所以,在这里,我比以前更加困惑在哪个方向上。虽然我非常喜欢设计原则,但现有框架的复杂性让我失望了!

我的担忧是真的吗?别人都有同感吗?如果是这样,对于如此大规模压倒性的“框架”,还有什么好的选择吗?

6 个答案:

答案 0 :(得分:3)

我个人非常喜欢使用Autofac。容器配置是通过代码完成的,同时消除了冗长的XML并支持重构支持。

最好的功能之一是modules。它们是容器配置的单元,允许您管理构成应用程序的许多不同组件的复杂性。

我目前正在开展一个非常大的项目,其经验大致与小时相同,这意味着这种方法可以很好地扩展。

启用DI的类的主要原则是它们不引用基础结构代码。这是服务定位器模式的对立面。 Service Locator的主要缺点是,除了为引用容器的类增加复杂性之外,还无法更改解析依赖项的哪个版本

对于不引用容器的“纯”类,任何给定依赖项的已解析版本都是正在注入的类的外部。

答案 1 :(得分:2)

正如Nate所说,“神奇”是可选的;如果需要,您可以手动配置所有内容。

我最初(或永远!)避免使用配置文件,并在代码中配置容器。这往往更容易阅读和维护。大多数情况下,您不需要对配置进行即时更改。客户无法触摸配置文件,因为它们不存在。

服务定位器有缺点;例如,他们倾向于将您的类耦合到定位器类/框架。一个好的DI框架可以让你使用Plain Old Objects;您的项目中可能只有一个实际使用DI / IoC框架的类。

StructureMap和Unity都非常简单;试一试。从小处开始。

以下是Unity的一个非常简单的示例(包括内联配置):

using Microsoft.Practices.Unity;

static void Main()
{
    using (IUnityContainer container = new UnityContainer())
    {
        container.RegisterType<IRobot, MrRoboto>();

        Console.WriteLine("Asking Unity container to give us a Model...");

        Model model = container.Resolve<Model>();
        model.MoveRobot();
    }
}

// class Model

public Model(IRobot robot)
{
    // Unity will hand the constructor an instance of MrRoboto!
}

答案 2 :(得分:2)

如果您真的想要进入依赖注入路线,我强烈建议您快速阅读Martin Fowler的优秀依赖注入文章:

http://martinfowler.com/articles/injection.html

我正在使用大量配置文件处理Java项目。我们选择使用Singleton模式来代表我们的配置(有点像全局解决方案)。这是让我疯狂的事情,让我希望我们有一个依赖注入模式:

  1. 全球化模式的单元测试很糟糕。依赖注入模式使得自己更容易进行单元测试,特别是模拟对象测试。在单例类型的情况下,您现在拥有所有这些单元测试仍然需要全局状态才能运行。通过依赖注入,您可以创建传递到测试中的特定于测试的模拟配置对象。我不能夸大这使得单元测试变得容易多了。另一篇优秀论文题为“内部测试:使用模拟对象进行单元测试”:http://connextra.com/aboutUs/mockobjects.pdf

  2. 使用全球化的方法在较小的系统中效果更好,但随着线程数量的增加,它们都开始竞争配置资源。您可能遇到同步问题,您的配置访问甚至可能开始成为瓶颈。这对我们来说还不是一个大问题,但它开始让我们所有人烦恼。

  3. 一旦你走了一条非依赖注射路线,就没有真正的回归。从依赖注入到某种全球化模式是令人讨厌的,但是可以逐步进行。试图从全球化模式回归依赖注入是一场噩梦。我一直想在我们的项目上做这件事而我不能。这需要整个开发周期。

  4. 无论如何,希望文章和经验可以帮助你做出决定。我在你正在考虑前进的道路上走了很长的路,而且我希望我们能够采取依赖注入路线:-D

答案 3 :(得分:1)

对于DI来说,这些都不是“必需的” - 它们是某些DI框架提供的选项。就个人而言,我也不喜欢“自动化”注入 - 我可以看到它适用于非常小的项目,但会导致大型项目出现问题。对于第2点 - 我不确定我是否明白 - 我主要使用Spring。 Spring提供XML和Java配置选项。它提供嵌套配置。如果您不希望任何人更改配置的一部分,并且您有一部分 - 将它们分成单独的配置文件 - 或者使“可更改”的一个XML和另一个Java。 Spring还支持使用属性文件中的值,这是我希望管理员改变的 - 管理员不是程序员 - 他们不应该“重新布线”你的应用程序 - 只是提供适当的选项。

答案 4 :(得分:0)

根据您使用的语言,有一些DI框架并不那么可怕,虽然您将有一些配置文件,但它们不应该是可怕的,但有用。

例如,我有一个用于开发的配置文件,一个用于测试,一个用于生产。

因此,根据我使用的那个,可以更改数据库连接,我可以换出数据库层进行测试,并使用模拟测试。

系统管理员应该控制生产配置文件,因为开发人员不应该将任何东西投入生产,理想情况下。

Spring有一个很好的DI设置,虽然它不是轻量级的。

我发现Unity Framework的学习并不容易,但是一旦你使用它,就很容易添加新的注入类。

所以,最初的任何新内容都可能是可怕的,但是当你对这个概念感到满意时,你可以看到优势,比如我解释了三个配置文件。

答案 5 :(得分:0)

我的情况可能与您的不同之处在于我们已经有一个专为非常灵活的配置而设计的系统,因此向该配置添加依赖注入几乎是微不足道的,但在我看来,使用服务定位器模式不会为您节省太多配置因为您仍必须指定如何查找服务。能够灵活地注入模拟对象进行测试对于使用依赖注入来说几乎是非常宝贵的好处,所以我认为配置开销可能只是为了获得收益而需要接受的业务成本。