为什么我需要一个IoC容器而不是简单的DI代码?

我一直在使用依赖注入(DI)一段时间,在构造函数,属性或方法中注入。 我从来没有觉得需要使用控制反转(IoC)容器。 然而,我读得越多,我感受到社区使用IoC容器的压力越大。

我使用了.NET容器,如StructureMap,NInject,Unity和Funq。 我仍然无法看到IoC容器如何使我的代码受益/改进。

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

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


哇,不能相信乔尔会赞成这个:

var svc = new ShippingService(new ProductLocator(), 
   new PricingService(), new InventoryService(), 
   new TrackingRepository(new ConfigProvider()), 
   new Logger(new EmailLogger(new ConfigProvider())));

在此:

var svc = IoC.Resolve<IShippingService>();

许多人没有意识到你的依赖关系链可以嵌套,并且手动将它们连接起来很快变得很难。 即使在工厂中,代码的重复也不值得。

IoC容器可能很复杂,是的。 但对于这个简单的例子,我已经证明它非常简单。


好的,让我们来证明这一点。 假设您有一些要绑定到智能UI的实体或模型对象。 这个智能UI(我们称之为Shindows Morms)希望你实现INotifyPropertyChanged,以便它可以相应地更改跟踪和更新UI。

“好吧,听起来不那么难”,所以你开始写作。

你从这开始:

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime CustomerSince { get; set; }
    public string Status { get; set; }
}

..和这样结束了:

public class UglyCustomer : INotifyPropertyChanged
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            string oldValue = _firstName;
            _firstName = value;
            if(oldValue != value)
                OnPropertyChanged("FirstName");
        }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set
        {
            string oldValue = _lastName;
            _lastName = value;
            if(oldValue != value)
                OnPropertyChanged("LastName");
        }
    }

    private DateTime _customerSince;
    public DateTime CustomerSince
    {
        get { return _customerSince; }
        set
        {
            DateTime oldValue = _customerSince;
            _customerSince = value;
            if(oldValue != value)
                OnPropertyChanged("CustomerSince");
        }
    }

    private string _status;
    public string Status
    {
        get { return _status; }
        set
        {
            string oldValue = _status;
            _status = value;
            if(oldValue != value)
                OnPropertyChanged("Status");
        }
    }

    protected virtual void OnPropertyChanged(string property)
    {
        var propertyChanged = PropertyChanged;

        if(propertyChanged != null)
            propertyChanged(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

这是令人厌恶的管道代码,我坚持认为,如果你手动编写这样的代码, 就会从客户端窃取 。 有更好,更聪明的工作方式。

听过这个词,工作更聪明,不难吗?

想象一下你们团队中的一些聪明人出现并说:“这是一个更简单的方法”

如果你让自己的属性变得虚拟(冷静下来,这不是什么大不了的),那么我们可以自动编织属性行为。 (这叫做AOP,但不要担心名字,专注于它会为你做什么)

根据您使用的IoC工具,您可以执行如下所示的操作:

var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper());

噗! 现在,所有该手动INotifyPropertyChanged BS都将自动为您在所讨论对象的每个虚拟属性设置器上自动生成。

这是神奇吗? ! 如果你可以相信这个代码完成它的工作,那么你可以安全地跳过所有包装mumbo-jumbo的属性。 你有业务问题需要解决。

IoC工具的一些其他有趣用途可用于执行AOP:

  • 声明性和嵌套数据库事务
  • 声明性和嵌套工作单元
  • 记录
  • 前/后条件(按合同设计)

  • 我和你在一起,瓦迪姆。 IoC容器采用了一个简单,优雅和有用的概念,并使它成为必须用200页的手册学习两天的东西。

    我个人对于IoC社区如何看待Martin Fowler的一篇精美优雅的文章感到困惑不解,并将其转变为一系列通常具有200-300页手册的复杂框架。

    我尽量不做评判(哈哈!),但我认为使用IoC容器的人是(A)非常聪明,(B)对那些不像他们那样聪明的人缺乏同情心。 一切都对他们很有意义,所以他们很难理解许多普通程序员会发现这些概念混淆。 这是知识的诅咒。 了解IoC容器的人很难相信有人不理解它。

    使用IoC容器最有价值的好处是您可以在一个地方配置一个配置开关,让您在测试模式和生产模式之间切换。 例如,假设您有两个版本的数据库访问类...一个版本积极记录并进行了大量验证,您在开发过程中使用了这些验证,另一个版本没有日志记录或验证,而且生产速度极快。 能够在一个地方切换它们是很好的。 另一方面,这是一个相当简单的问题,不需要IoC容器的复杂性就能以简单的方式处理。

    我相信,如果你使用IoC容器,坦率地说,你的代码变得难以阅读。 你必须查看哪些地方来弄清楚代码要做什么,至少增加一个。 在天堂的某个地方,一位天使在哭泣。


    想必没有人强迫你使用DI容器框架。 您已经在使用DI来分离您的课程并提高可测试性,因此您可以获得很多好处。 总之,你赞成简单,这通常是一件好事。

    如果您的系统达到手动DI变得繁琐(即增加维护)的复杂程度,请根据DI容器框架的团队学习曲线权衡这一点。

    如果您需要更多地控制依赖项生命周期管理(也就是说,如果您觉得需要实现Singleton模式),请查看DI容器。

    如果您使用DI容器,请仅使用您需要的功能。 跳过XML配置文件并在代码中进行配置(如果足够的话)。 坚持构造器注入。 Unity或StructureMap的基础可以精简为几页。

    Mark Seemann在此发表了一篇很棒的博客文章:何时使用DI容器

    链接地址: http://www.djcxy.com/p/14419.html

    上一篇: Why do I need an IoC container as opposed to straightforward DI code?

    下一篇: How to use PHP classes between other classes