我已经使用依赖注入(DI)有一段时间了,在构造函数、属性或方法中进行注入。我从未觉得有必要使用反转控制(IoC)容器。然而,我读得越多,我就越感到来自社区的使用IoC容器的压力。
我使用过StructureMap、NInject、Unity和Funq等。net容器。我仍然没有看到IoC容器将如何受益/改进我的代码。
我也害怕在工作中开始使用容器,因为我的许多同事会看到他们不理解的代码。他们中的许多人可能不愿意学习新技术。
请说服我,我需要使用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的最大好处是能够集中配置依赖项。
如果你正在使用依赖注入,你的代码可能是这样的
public class CustomerPresenter
{
public CustomerPresenter() : this(new CustomerView(), new CustomerService())
{}
public CustomerPresenter(ICustomerView view, ICustomerService service)
{
// init view/service fields
}
// readonly view/service fields
}
如果你使用静态IoC类,而不是(恕我直言)更混乱的配置文件,你可以有这样的东西:
public class CustomerPresenter
{
public CustomerPresenter() : this(IoC.Resolve<ICustomerView>(), IoC.Resolve<ICustomerService>())
{}
public CustomerPresenter(ICustomerView view, ICustomerService service)
{
// init view/service fields
}
// readonly view/service fields
}
然后,你的静态IoC类看起来像这样,我在这里使用Unity。
public static IoC
{
private static readonly IUnityContainer _container;
static IoC()
{
InitializeIoC();
}
static void InitializeIoC()
{
_container = new UnityContainer();
_container.RegisterType<ICustomerView, CustomerView>();
_container.RegisterType<ICustomerService, CustomerService>();
// all other RegisterTypes and RegisterInstances can go here in one file.
// one place to change dependencies is good.
}
}
我支持你,瓦迪姆。IoC容器采用了一个简单、优雅且有用的概念,并使其成为您需要用200页手册学习两天的东西。
我个人很困惑,为什么IoC社区把Martin Fowler写的一篇漂亮、优雅的文章变成了一堆复杂的框架,通常只有200-300页的手册。
我尽量不去评判(哈哈!),但我认为使用IoC容器的人(A)非常聪明,(B)对不如他们聪明的人缺乏同理心。对他们来说,每件事都很有意义,所以他们很难理解许多普通程序员会感到困惑的概念。这是知识的诅咒。理解IoC容器的人很难相信还有人不理解它。
The most valuable benefit of using an IoC container is that you can have a configuration switch in one place which lets you change between, say, test mode and production mode. For example, suppose you have two versions of your database access classes... one version which logged aggressively and did a lot of validation, which you used during development, and another version without logging or validation that was screamingly fast for production. It is nice to be able to switch between them in one place. On the other hand, this is a fairly trivial problem easily handled in a simpler way without the complexity of IoC containers.
我相信如果您使用IoC容器,您的代码将变得(坦白地说)难以阅读。为了弄清楚代码要做什么,您必须查看的地方的数量至少增加了一个。在天堂的某个地方,一位天使在呼喊。