我已经使用依赖注入(DI)有一段时间了,在构造函数、属性或方法中进行注入。我从未觉得有必要使用反转控制(IoC)容器。然而,我读得越多,我就越感到来自社区的使用IoC容器的压力。

我使用过StructureMap、NInject、Unity和Funq等。net容器。我仍然没有看到IoC容器将如何受益/改进我的代码。

我也害怕在工作中开始使用容器,因为我的许多同事会看到他们不理解的代码。他们中的许多人可能不愿意学习新技术。

请说服我,我需要使用IoC容器。当我在工作中与其他开发人员交谈时,我将使用这些论点。


当前回答

我知道这是一个相当老的帖子,但它似乎仍然相当活跃,我想我可以贡献一些在其他回答中没有提到的观点。

我同意依赖注入的好处,但我更喜欢自己构造和管理对象,使用与Maxm007在回答中概述的模式相似的模式。我发现了使用第三方容器的两个主要问题:

1) Having a 3rd party library manage the lifetime of your objects "automagically" can lend itself to unexpected results. We have found that especially in large projects, you can have vastly more copies of an object than you expect, and more than you would if you were manually managing the lifecycles. I'm sure this varies depending on the framework used, but the problem exists nonetheless. This can also be problematic if your object holds resources, data connections, etc., since the object can sometimes live longer than you expect. So inevitably, IoC containers tend to increase the resource utilization and memory footprint of an application.

2) IoC containers, in my opinion, are a form of "black box programming". I have found that in particular, our less experienced developers tend to abuse them. It allows the programmer to not have to think about how objects should relate to each other or how to decouple them, because it provides them with a mechanism in which they can simply grab any object they want out of thin air. Eg, there may be a good design reason that ObjectA should never know about ObjectB directly, but rather than creating a factory or bridge or service locator, an inexperienced programmer will simply say "no problem, I'll just grab ObjectB from the IoC container". This can actually lead to increased object coupling, which is what IoC is supposed to help prevent.

其他回答

无论何时使用“new”关键字,您都是在创建一个具体的类依赖,您的头脑中应该敲响警钟。孤立地测试这个物体变得更加困难。解决方案是对接口进行编程并注入依赖项,这样对象就可以用实现该接口的任何东西进行单元测试。模拟)。

The trouble is you have to construct objects somewhere. A Factory pattern is one way to shift the coupling out of your POXOs (Plain Old "insert your OO language here" Objects). If you and your co-workers are all writing code like this then an IoC container is the next "Incremental Improvement" you can make to your codebase. It'll shift all that nasty Factory boilerplate code out of your clean objects and business logic. They'll get it and love it. Heck, give a company talk on why you love it and get everyone enthused.

如果你的同事还没有做DI,那么我建议你先专注于DI。宣传如何编写易于测试的干净代码。干净的DI代码是比较困难的部分,一旦做到了这一点,将对象连接逻辑从Factory类转移到IoC容器应该是相对简单的。

我认为IoC的大部分价值都是通过使用DI获得的。既然你已经这样做了,剩下的好处是递增的。

你得到的值将取决于你正在处理的应用程序的类型:

For multi-tenant, the IoC container can take care of some of the infrastructure code for loading different client resources. When you need a component that is client specific, use a custom selector to do handle the logic and don't worry about it from your client code. You can certainly build this yourself but here's an example of how an IoC can help. With many points of extensibility, the IoC can be used to load components from configuration. This is a common thing to build but tools are provided by the container. If you want to use AOP for some cross-cutting concerns, the IoC provides hooks to intercept method invocations. This is less commonly done ad-hoc on projects but the IoC makes it easier.

我以前写过这样的功能,但如果我现在需要这些功能中的任何一个,我宁愿使用一个预先构建并经过测试的工具,如果它适合我的架构的话。

正如其他人所提到的,您还可以集中配置希望使用的类。虽然这可能是一件好事,但代价是误导和复杂化。大多数应用程序的核心组件都没有被替换,因此很难做出取舍。

我使用IoC容器,并欣赏其功能,但不得不承认我注意到了权衡:我的代码在类级别变得更加清晰,而在应用程序级别变得不那么清晰(即可视化控制流)。

IoC框架非常棒,如果你想…

…扔掉类型安全。许多(?)IoC框架迫使您执行代码,如果您想确保所有东西都正确连接。“嘿!希望我已经把一切都设置好了,这样我对这100个类的初始化就不会在生产中失败,抛出空指针异常!” ...在代码中使用全局变量(IoC框架都是关于改变全局状态的)。 ...编写依赖关系不明确、难以重构的蹩脚代码,因为你永远不知道什么依赖什么。

IoC的问题在于,使用它的人过去常常编写这样的代码

public class Foo {
    public Bar Apa {get;set;}
    Foo() {
        Apa = new Bar();
    }
}

这显然是有缺陷的,因为Foo和Bar之间的依赖是硬连接的。然后他们意识到编写这样的代码会更好

public class Foo {
    public IBar Apa {get;set;}
    Foo() {
        Apa = IoC<IBar>();
    }
}

这也有缺陷,但不那么明显。 在Haskell中,Foo()的类型将是IO Foo,但你真的不想要IO部分,这应该是一个警告信号,如果你得到了它,你的设计有问题。

为了摆脱它(io部分),获得ioc框架的所有优点,去掉它的所有缺点,你可以使用抽象工厂。

正确的解决方法应该是

data Foo = Foo { apa :: Bar }

或者

data Foo = forall b. (IBar b) => Foo { apa :: b }

和inject(但我不会叫它inject) Bar。

另外:观看Erik Meijer (LINQ的发明者)的视频,他说DI是为不懂数学的人准备的(我非常同意):http://www.youtube.com/watch?v=8Mttjyf-8P4

不像Spolsky先生,我不相信使用ioc框架的人很聪明——我只是认为他们不懂数学。

都快三年了,是吧?

在支持IoC框架的评论中,有50%的人不理解IoC和IoC框架之间的区别。我怀疑他们是否知道无需部署到应用服务器就可以编写代码 如果我们以最流行的Java Spring框架为例,IoC配置从XMl转移到代码中,现在看起来是这样的

“@ configuration 公共类AppConfig {

public @Bean TransferService transferService() {
    return new TransferServiceImpl(accountRepository());
}

public @Bean AccountRepository accountRepository() {
    return new InMemoryAccountRepository();
}

} ` 我们需要一个框架来做这件事,为什么?

在我看来,您已经构建了自己的IoC容器(使用Martin Fowler描述的各种模式),并且正在询问为什么其他人的实现比您的更好。

所以,你有一堆已经工作的代码。并且想知道为什么要用其他人的实现来替换它。

考虑第三方IoC容器的优点

你可以免费修理bug 图书馆的设计可能比你的好 人们可能已经熟悉了特定的库 图书馆可能比你的快 它可能有一些您希望实现但没有时间实现的特性(您有服务定位器吗?)

Cons

你可以免费引入bug:) 图书馆的设计可能比你的还差 你必须学习一个新的API 太多你永远不会用到的功能 调试不是你写的代码通常比较困难 从以前的IoC容器迁移可能很乏味

所以,权衡利弊,做出决定吧。