我已经使用依赖注入(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可能不好。

As with everything else, IOC container (or as Einstein would put it I=OC^2) is a concept you have to decide for yourself if you need it or not in your code. Recent fashion outcry about IOC is only that, fashion. Don't fall for fashion, that is first. There are myriads of concepts out there you could implement in your code. First of all, I am using dependency injection since I have started programming, and learned the term itself when it was popularized under that name. Dependency control is a very old subject and it was addressed so far in trillions of ways, depending on what was decoupling from what. Decoupling everything from everything is a nonsense. The problem with IOC container is that it tries to be as useful as Entity Framework or NHibernate. While writing an object-relational mapper is simply a must as soon as you have to couple any database with your system, IOC container is not always necessary. So when IOC container is useful:

当你有很多依赖的情况,你想组织 当你不关心你的代码与第三方产品的耦合时 当您的开发人员想要学习如何使用新工具时

1:在你的代码中有这么多依赖关系并不常见,或者你在设计的早期就意识到了它们。当需要抽象思维时,抽象思维是有用的。

2:将你的代码与第三方代码耦合是一个巨大的问题。我使用的是10多年前的代码,当时遵循的是ATL、COM、COM+等花哨而先进的概念。现在你对这些代码无能为力了。我想说的是,一个先进的概念会带来明显的优势,但从长远来看,这种优势本身就过时了。这只会让一切都变得更贵。

3: Software development is hard enough. You can extend it to unrecognizable levels if you allow some advanced concept to crop into your code. There is a problem with IOC2. Although it is decoupling dependencies, it is decoupling the logic flow as well. Imagine you have found a bug and you need to set a break to examine the situation. IOC2, as any other advanced concept, is making that more difficult. Fixing a bug within a concept is more difficult than fixing a bug in a plainer code, because when you fix a bug a concept must be obeyed again. (Just to give you an example, C++ .NET is constantly changing the syntax so much that you need to think hard before you refactor some older version of .NET.) So what is the problem with IOC? The problem is in resolving dependencies. The logic for resolving is commonly hidden in the IOC2 itself, written maybe in uncommon way that you need to learn and maintain. Will your third-party product be there in 5 years? Microsoft's was not.

"We know how" syndrome is written all over the place regarding IOC2. This is similar to automation testing. Fancy term and perfect solution at first glance, you simply put all your tests to execute over night and see the results in the morning. It is really painful to explain company after company what automated testing really means. Automated testing is definitely not a quick way of reducing the number of bugs which you can introduce overnight to increase the quality of your product. But, fashion is making that notion annoyingly dominant. IOC2 suffers the same syndrome. It is believed that you need to implement it in order your software to be good. EvErY recent interview I was asked if I am implementing IOC2 and automation. That is a sign of fashion: the company had some part of code written in MFC they will not abandon.

你需要像学习软件中的其他概念一样学习IOC2。是否需要使用IOC2是由团队和公司内部决定的。但是,在做出决定之前,至少必须提到以上所有的理由。只有当你看到积极的一面超过消极的一面,你才能做出积极的决定。

There is nothing wrong with IOC2 except that it does solve only the problems it solves and introduces the problems it introduces. Nothing else. However, going against the fashion is very difficult, they have sweat mouth, the followers of anything. It is strange how none of them is there when the problem with their fanciness becomes apparent. Many concepts in software industry have been defended because they create profit, books are written, conferences held, new products made. That is fashion, usually short lived. As soon as people find something else they abandon it completely. IOC2 is useful but it shows the same signs as many other vanished concepts I have seen. I do not know if it will survive. There is no rule for that. You think if it is useful, it will survive. No, it does not go that way. One big rich company is enough and the concept can die within few weeks. We'll see. NHibernate survived, EF came second. Maybe IOC2 will survive too. Do not forget that most concepts in software development are about nothing special, they are very logical, simple and obvious, and sometimes it is more difficult to remember the current naming convention than to understand the concept itself. Does the knowledge of IOC2 make a developer a better developer? No, because if a developer was not able to come up with a concept similar in nature to IOC2 then it will be difficult for him or her to understand which problem IOC2 is solving, using it will look artificial and he or she may start using it for sake of being some sort of politically correct.

在我看来,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.
   }
}

我是声明式编程的爱好者(看看我回答了多少SQL问题),但我所研究的IoC容器似乎太神秘了。

...或者IoC容器的开发人员无法编写清晰的文档。

...或者两者在某种程度上都是正确的。

我不认为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容器的最大好处(我个人使用Ninject)是消除了设置和其他类型的全局状态对象的传递。

我不为web编程,我的是一个控制台应用程序,在对象树的许多地方,我需要访问用户指定的设置或元数据,这些设置或元数据是在对象树的一个完全独立的分支上创建的。通过IoC,我简单地告诉Ninject将设置作为一个单例(因为它们总是只有一个实例),在构造函数中请求设置或字典,然后立即…它们在我需要的时候神奇地出现了!

如果不使用IoC容器,我将不得不通过2,3,…传递设置和/或元数据。在它被需要它的对象实际使用之前,有n个对象。

DI/IoC容器还有许多其他好处,正如其他人在这里详细介绍的那样,从创建对象到请求对象的想法可能会令人难以置信,但使用DI对我和我的团队非常有帮助,所以也许您可以将其添加到您的库中!