【问题标题】:Why not pass your IoC container around?为什么不传递你的 IoC 容器呢?
【发布时间】:2010-11-15 22:37:02
【问题描述】:

在这个 AutoFac“最佳实践”页面 (http://code.google.com/p/autofac/wiki/BestPractices) 上,他们说:

不要传递容器 让组件访问容器,或将其存储在公共静态属性中,或使 Resolve() 等函数在全局“IoC”类上可用,都违背了使用依赖注入的目的。这样的设计与服务定位器模式有更多的共同点。 如果组件依赖于容器,请查看它们如何使用容器来检索服务,并将这些服务添加到组件的(依赖注入的)构造函数参数中。

那么让一个组件“动态”实例化另一个组件的更好方法是什么?他们的第二段没有涵盖“可能”需要创建的组件将取决于系统状态的情况。或者当组件A需要创建X个组件B时。

【问题讨论】:

    标签: dependency-injection inversion-of-control


    【解决方案1】:

    Service Locator 模式更难测试,当然也更难控制依赖关系,这可能会导致系统中的耦合超出您的实际预期。

    如果你真的想要惰性实例化之类的东西,你仍然可以选择 Service Locator 样式(它不会立即杀死你,如果你坚持使用容器的接口,使用一些模拟框架进行测试并不难)。请记住,尽管在构造函数中不做太多(或任何事情)的类的实例化非常便宜。

    我所知道的容器(目前还不是 autofac)可以让您根据系统的状态修改哪些依赖项应该注入到哪个实例中,这样即使这些决定也可以外部化到容器的配置中。

    这可以为您提供很大的灵活性,而无需根据您在实例消费依赖项中访问的某些状态来实现与容器的交互。

    【讨论】:

    • 最后一段有人看懂了吗?
    • @msfanboy - 是的,这很难。我不得不把它读了三遍,并在心里停顿了一下,把这段话分成了一些容易理解的部分。但也许那是因为英语不是我的母语:D
    【解决方案2】:

    Autofac 实际上为这种情况提供了一些特殊功能 - 详细信息请参见此处的 wiki:http://code.google.com/p/autofac/wiki/DelegateFactories。

    本质上,如果 A 需要创建 B 的多个实例,A 可以依赖 Func,Autofac 将生成一个从容器中返回新 B 的实现。

    上面的其他建议当然是有效的 - Autofac 的方法有几个不同之处:

    • 它避免了对大量工厂接口的需要
    • B(工厂的产品)仍然​​可以有容器注入的依赖项

    希望这会有所帮助!

    尼克

    【讨论】:

    • Unity 也支持这样的自动工厂。
    • 许多容器现在都这样做了——Funq 和 Autofac 开始了这项工作,但它已成为一种相当标准的方法。
    • 此处答案中的链接已弃用 - 这似乎是 Autofac autofaccn.readthedocs.io/en/latest/advanced/… 中对 DelegateFactories 的更新引用
    【解决方案3】:

    要抽象出另一个组件的实例化,您可以使用工厂模式:

    public interface IComponentBFactory
    {
        IComponentB CreateComponentB();
    }
    
    public class ComponentA : IComponentA
    {
        private IComponentBFactory _componentBFactory;
    
        public ComponentA(IComponentBFactory componentBFactory)
        {
            _componentBFactory = componentBFactory;
        }
    
        public void Foo()
        {
            var componentB = _componentBFactory.CreateComponentB();
    
            ...
        }
    }
    

    然后可以将实现注册到 IoC 容器中。

    容器是组合对象图的一种方式,但它肯定不是唯一的方式。这是一个实现细节。使对象不受这些知识的影响,使它们与基础设施问题脱钩。它还使他们不必知道要解决的依赖项的哪个版本。

    【讨论】:

    • 我打算提出同样的建议。这是我认为的方式。
    • 好答案布莱恩。我实际上知道答案......但提出问题似乎是我开始在 StackOverflow 系统上获得积分的唯一方法。很好的解释!
    【解决方案4】:

    IoC 负责确定给定对象应使用哪个版本的依赖项。这对于创建实现接口的对象链以及依赖于该接口(类似于命令链或装饰器模式)等操作很有用。

    通过传递您的容器,您将责任放在单个对象上以获取适当的依赖项,因此它必须知道如何去做。对于典型的 IoC 用法,对象只需要声明它具有一个依赖项,而不是考虑在该依赖项的多个可用实现之间进行选择。

    【讨论】:

      猜你喜欢
      • 2014-04-29
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      • 2013-01-12
      • 1970-01-01
      • 1970-01-01
      • 2011-01-17
      • 2013-12-24
      相关资源
      最近更新 更多