默认构造函数与IOC容器

时间:2008-09-19 10:16:35

标签: inversion-of-control

有人可以向我解释使用IOC容器而不是简单地将默认实现硬编码到默认构造函数中的优势吗?

换句话说,这段代码有什么问题?

public class MyClass
{
    private IMyInterface _myInterface;

    public MyClass()
    {
        _myInterface = new DefaultMyInterface();
    }

    public MyClass(IMyInterface myInterface)
    {
        _myInterface = myInterface;
    }
}

据我所知,这个类足够支持构造函数注入,因此可以轻松完成单元测试和模拟。除此之外,默认构造函数删除了IOC容器的计算开销(更不用说整个过程更加透明)。

我可以看到使用IOC容器的唯一好处是,如果您需要经常切换接口的实现。我错过了什么吗?

8 个答案:

答案 0 :(得分:12)

IoC的想法是将组件的部分功能委托给系统的另一部分。在IoC世界中,您拥有彼此不了解的组件。您的示例违反了这一点,因为您在MyClass和IMyInterface的某些实现之间创建紧密耦合。 主要想法是您的组件不知道将如何使用它。在您的示例中,您的组件会对其使用做出一些假设

实际上这种方法可行,但混合使用IoC和显式对象初始化并不是IMO的好习惯。

IoC通过以代码清晰度的代价执行后期绑定来为您提供松耦合。当您向此进程添加其他行为时,它会使事情变得更加复杂,并且当某些组件可能会收到具有不需要或不可预测的行为的对象时,可能会导致错误。

答案 1 :(得分:4)

选择一方:)

简而言之,建议使用IOC。代码的问题在于,我无法在不重新编译代码的情况下交换依赖项的默认实现,如最后所述。 IOC允许您在外部文件中更改对象的配置或组合,而无需重新编译 IOC从其余代码中接管“建筑和装配”责任。 IOC的目的不是让您的代码可测试......这是一个令人愉快的副作用。 (就像TDDed代码导致更好的设计)

答案 2 :(得分:2)

此代码没有任何问题,您仍然可以将它与Spring和Guice等依赖注入框架一起使用。

许多开发人员认为Spring的XML配置文件优于代码中的布线依赖关系,因为您可以在不需要编译步骤的情况下切换实现。实际上,这种好处是在您已经在类路径中编译了多个实现并且希望在部署时选择实现的情况下实现的。您可以想象部署后第三方提供组件的情况。类似地,可能存在一种情况,您希望在部署后将其他实现作为补丁发布。

但并非所有DI框架都使用XML配置。例如,Google Guice将模块编写为Java类,必须像任何其他java类一样进行编译。

如果您甚至需要编译步骤,那么DI的优势是什么? 这将我们带回原始问题。 我可以看到以下优点:

  1. 整个申请过程中DI的标准方法。
  2. 配置与其他逻辑完全分开。
  3. 注入代理的能力。例如,Spring允许您通过注入代理而不是实现来执行声明式事务处理
  4. 更容易重复使用配置逻辑。当你广泛使用DI时,你会看到一个复杂的依赖关系树随着时间的推移而发展。没有明确分离的配置层和框架支持来管理它可能是一场噩梦。 DI框架可以通过继承和其他方式轻松重用配置逻辑。

答案 3 :(得分:2)

我唯一担心的是(1)如果您的默认服务依赖项本身具有另一个/辅助服务依赖项(依此类推......您的DefaultMyInterface依赖于ILogger)和(2)您需要将第一个服务依赖项与第二个(需要使用存根ILogger测试DefaultMyInterface)。在这种情况下,您显然需要丢失默认的“new DefaultMyInterface”,而是执行以下操作之一:(1)纯依赖注入或(2)服务定位器或(3)container.BuildUp(new DefaultMyInterface());

列出的其他海报的一些问题可能对您的问题不公平。你没有问过多个“生产”实现。你在询问单元测试。在单元测试你的方法的情况下,我的第一个警告说,似乎合法;我也会考虑在简单的单元测试用例中使用它。

同样,一对响应者对重新表现表示担忧。我也不喜欢重复,但如果(1)你的默认实现确实是你的默认(YAGNI:你没有改变默认的计划)和(2)你不相信我说的第一个警告适用和(3)更喜欢你所分享的更简单的代码方法,然后我认为这种特殊的重复形式不是问题。

答案 4 :(得分:1)

除了松耦合外,IoC还可以减少代码重复。当您使用IoC并且想要更改界面的默认实现时,您必须仅在一个位置更改它。当您使用默认构造函数注入默认实现时,您必须在使用该接口的任何位置更改它。

答案 5 :(得分:1)

除了其他评论之外,在这些情况下,人们可以争论DRY(不要重复自己)原则。它必须将默认构造代码放在每个类中。它也是介绍特殊情况处理,不需要任何。

答案 6 :(得分:0)

我不明白为什么你的默认实现硬编码技术不能与IOC容器一起使用。只是,您未在配置中指定的依赖项将采用默认实现。

或者我错过了什么?

答案 7 :(得分:0)

您可能想要使用IOC容器的一个原因是为了方便软件的后期配置。

例如,假设您提供了特定接口的多个实现 - 客户(或您的专业服务团队)可以通过修改IOC配置文件来决定使用哪个接口。