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

Dependency injection 为什么我需要一个IoC容器而不是简单的DI代码?,dependency-injection,inversion-of-control,ioc-container,Dependency Injection,Inversion Of Control,Ioc Container,我已经使用(DI)一段时间了,在构造函数、属性或方法中注入。我从未觉得有必要使用(IoC)容器。然而,我读得越多,我就越感觉到来自社区使用IoC容器的压力 我使用了.NET容器,如、、和。我仍然看不到IoC容器将如何帮助/改进我的代码 我也害怕在工作中开始使用容器,因为我的许多同事会看到他们不理解的代码。他们中的许多人可能不愿意学习新技术 请让我相信我需要使用IoC容器。我将在与同事交谈时使用这些论点。在我看来,IoC的首要好处是能够集中配置依赖项 如果您当前正在使用依赖项注入,那么您的代码可能

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

我使用了.NET容器,如、、和。我仍然看不到IoC容器将如何帮助/改进我的代码

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


请让我相信我需要使用IoC容器。我将在与同事交谈时使用这些论点。

在我看来,IoC的首要好处是能够集中配置依赖项

如果您当前正在使用依赖项注入,那么您的代码可能如下所示

public class Foo {
    public Bar Apa {get;set;}
    Foo() {
        Apa = new Bar();
    }
}
公共类CustomerPresenter
{
公共CustomerPresenter():此(新CustomerView(),新CustomerService())
{}
公共CustomerPresenter(ICCustomerView视图、ICCustomerService服务)
{
//初始化视图/服务字段
}
//只读视图/服务字段
}
如果您使用的是静态IoC类,而不是更混乱的配置文件,那么您可能会有如下内容:

interface IServiceA { }
interface IServiceB { }
class ServiceA : IServiceA { }
class ServiceB : IServiceB { }

class StubServiceA : IServiceA { }
class StubServiceB : IServiceB { }

interface IRoot { IMiddle Middle { get; set; } }
interface IMiddle { ILeaf Leaf { get; set; } }
interface ILeaf { }

class Root : IRoot
{
    public IMiddle Middle { get; set; }

    public Root(IMiddle middle)
    {
        Middle = middle;
    }

}

class Middle : IMiddle
{
    public ILeaf Leaf { get; set; }

    public Middle(ILeaf leaf)
    {
        Leaf = leaf;
    }
}

class Leaf : ILeaf
{
    IServiceA ServiceA { get; set; }
    IServiceB ServiceB { get; set; }

    public Leaf(IServiceA serviceA, IServiceB serviceB)
    {
        ServiceA = serviceA;
        ServiceB = serviceB;
    }
}


interface IApplicationFactory
{
    IRoot CreateRoot();
}

abstract class ApplicationAbstractFactory : IApplicationFactory
{
    protected abstract IServiceA ServiceA { get; }
    protected abstract IServiceB ServiceB { get; }

    protected IMiddle CreateMiddle()
    {
        return new Middle(CreateLeaf());
    }

    protected ILeaf CreateLeaf()
    {
        return new Leaf(ServiceA,ServiceB);
    }


    public IRoot CreateRoot()
    {
        return new Root(CreateMiddle());
    }
}

class ProductionApplication : ApplicationAbstractFactory
{
    protected override IServiceA ServiceA
    {
        get { return new ServiceA(); }
    }

    protected override IServiceB ServiceB
    {
        get { return new ServiceB(); }
    }
}

class FunctionalTestsApplication : ApplicationAbstractFactory
{
    protected override IServiceA ServiceA
    {
        get { return new StubServiceA(); }
    }

    protected override IServiceB ServiceB
    {
        get { return new StubServiceB(); }
    }
}


namespace ConsoleApplication5
{
    class Program
    {
        static void Main(string[] args)
        {
            var factory = new ProductionApplication();
            var root = factory.CreateRoot();

        }
    }

    //[TestFixture]
    class FunctionalTests
    {
        //[Test]
        public void Test()
        {
            var factory = new FunctionalTestsApplication();
            var root = factory.CreateRoot();
        }
    }
}
公共类CustomerPresenter
{
public CustomerPresenter():这(IoC.Resolve(),IoC.Resolve())
{}
公共CustomerPresenter(ICCustomerView视图、ICCustomerService服务)
{
//初始化视图/服务字段
}
//只读视图/服务字段
}
然后,你的静态IoC类会像这样,我在这里使用Unity

公共静态IoC
{
专用静态只读IUnityContainer\u容器;
静态IoC()
{
初始化ioc();
}
静态void InitializeIoC()
{
_容器=新的UnityContainer();
_container.RegisterType();
_container.RegisterType();
//所有其他RegisterType和RegisterInstance都可以放在一个文件中。
//一个改变依赖关系的地方是好的。
}
}

因为所有依赖项都是清晰可见的,所以它促进了创建松散耦合的组件,同时易于在整个应用程序中访问和重用。

使用容器主要是从命令式/脚本式的初始化和配置更改为声明式的。这可能有一些不同的有益效果:

  • 减少主程序启动例程
  • 支持相当深入的部署时间重新配置功能
  • 使依赖注入样式成为新工作阻力最小的路径
当然,可能会有困难:

  • 需要复杂启动/关闭/生命周期管理的代码可能不容易适应容器
  • 您可能需要处理任何个人、流程和团队文化问题,但这就是为什么您要问
  • 一些工具包本身也在迅速变得重量级,鼓励了许多DI容器一开始就强烈反对的那种深度依赖

    • 我支持你,瓦迪姆。IoC容器采用了一个简单、优雅和有用的概念,并使其成为您必须使用200页手册学习两天的内容

      我个人对国际奥委会社区如何将一个漂亮的框架变成一堆复杂的框架(通常有200-300页的手册)感到困惑

      我尽量不做评判(哈哈!),但我认为使用IoC容器的人(A)非常聪明,(B)对不如自己聪明的人缺乏同情心。对他们来说,一切都很有意义,因此他们很难理解许多普通程序员会发现这些概念令人困惑。这是最重要的。理解IoC容器的人很难相信有人不理解它

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


      我相信如果你使用IoC容器,坦白地说,你的代码会变得更难阅读。您必须查看的位置数至少增加了一个,以确定代码试图执行的操作。在天堂的某个地方,一位天使在呼喊。

      我是声明式编程的粉丝(看看我回答了多少SQL问题),但我所看到的IoC容器似乎太神秘了,不利于它们自己

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

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

      我认为IoC容器的概念并不坏。但实现必须既强大(也就是说,灵活),足以在各种各样的应用程序中使用,又简单易懂


      可能是六个一个半打另一个。一个真正的应用程序(不是玩具或演示)必然是复杂的,需要考虑到许多特殊情况和规则的例外情况。要么将复杂性封装在命令式代码中,要么封装在声明性代码中。但是您必须在某个地方表示它。

      IoC容器也适用于加载嵌套较深的类依赖项。例如,如果您有以下使用依赖注入的代码

      public void GetPresenter()
      {
      var presenter=新的CustomerPresenter(新Cu
      
      data Foo = Foo { apa :: Bar }
      
      data Foo = forall b. (IBar b) => Foo { apa :: b }
      
      var merger = new SimpleWorkflowInstanceMerger(
          new BitFactoryLog(typeof(SimpleWorkflowInstanceMerger).FullName), 
          new WorkflowAnswerRowUtil(
              new WorkflowFieldAnswerEntMapper(),
              new ActivityFormFieldDisplayInfoEntMapper(),
              new FieldEntMapper()),
          new AnswerRowMergeInfoRepository());
      
      public class MyController : Controller
      {
          private readonly ISimpleWorkflowInstanceMerger _simpleMerger;
          public MyController()
          {
              _simpleMerger = new SimpleWorkflowInstanceMerger(
                  new BitFactoryLog(typeof(SimpleWorkflowInstanceMerger).FullName), 
                  new WorkflowAnswerRowUtil(
                      new WorkflowFieldAnswerEntMapper(),
                      new ActivityFormFieldDisplayInfoEntMapper(),
                      new FieldEntMapper()),
                  new AnswerRowMergeInfoRepository())
          }
          ...
      }
      
      public MyController : Controller
      {
          private readonly ISimpleWorkflowInstanceMerger _simpleMerger;
          public MyController(ISimpleWorkflowInstanceMerger simpleMerger)
          {
              _simpleMerger = simpleMerger;
          }
          ...
      }
      
      interface IServiceA { }
      interface IServiceB { }
      class ServiceA : IServiceA { }
      class ServiceB : IServiceB { }
      
      class StubServiceA : IServiceA { }
      class StubServiceB : IServiceB { }
      
      interface IRoot { IMiddle Middle { get; set; } }
      interface IMiddle { ILeaf Leaf { get; set; } }
      interface ILeaf { }
      
      class Root : IRoot
      {
          public IMiddle Middle { get; set; }
      
          public Root(IMiddle middle)
          {
              Middle = middle;
          }
      
      }
      
      class Middle : IMiddle
      {
          public ILeaf Leaf { get; set; }
      
          public Middle(ILeaf leaf)
          {
              Leaf = leaf;
          }
      }
      
      class Leaf : ILeaf
      {
          IServiceA ServiceA { get; set; }
          IServiceB ServiceB { get; set; }
      
          public Leaf(IServiceA serviceA, IServiceB serviceB)
          {
              ServiceA = serviceA;
              ServiceB = serviceB;
          }
      }
      
      
      interface IApplicationFactory
      {
          IRoot CreateRoot();
      }
      
      abstract class ApplicationAbstractFactory : IApplicationFactory
      {
          protected abstract IServiceA ServiceA { get; }
          protected abstract IServiceB ServiceB { get; }
      
          protected IMiddle CreateMiddle()
          {
              return new Middle(CreateLeaf());
          }
      
          protected ILeaf CreateLeaf()
          {
              return new Leaf(ServiceA,ServiceB);
          }
      
      
          public IRoot CreateRoot()
          {
              return new Root(CreateMiddle());
          }
      }
      
      class ProductionApplication : ApplicationAbstractFactory
      {
          protected override IServiceA ServiceA
          {
              get { return new ServiceA(); }
          }
      
          protected override IServiceB ServiceB
          {
              get { return new ServiceB(); }
          }
      }
      
      class FunctionalTestsApplication : ApplicationAbstractFactory
      {
          protected override IServiceA ServiceA
          {
              get { return new StubServiceA(); }
          }
      
          protected override IServiceB ServiceB
          {
              get { return new StubServiceB(); }
          }
      }
      
      
      namespace ConsoleApplication5
      {
          class Program
          {
              static void Main(string[] args)
              {
                  var factory = new ProductionApplication();
                  var root = factory.CreateRoot();
      
              }
          }
      
          //[TestFixture]
          class FunctionalTests
          {
              //[Test]
              public void Test()
              {
                  var factory = new FunctionalTestsApplication();
                  var root = factory.CreateRoot();
              }
          }
      }
      
      public @Bean TransferService transferService() {
          return new TransferServiceImpl(accountRepository());
      }
      
      public @Bean AccountRepository accountRepository() {
          return new InMemoryAccountRepository();
      }