在这个AutoFac“最佳实践”页面(http://code.google.com/p/autofac/wiki/BestPractices)上,他们说:
不要传递容器 为组件提供对容器的访问权限,或将其存储在公共静态属性中,或者在全局“IoC”类上使用Resolve()等函数会失败使用依赖项注入的目的。这种设计与服务定位器模式有更多共同之处。 如果组件依赖于容器,请查看它们如何使用容器来检索服务,并将这些服务添加到组件(依赖注入)构造函数参数中。
那么让一个组件“动态”实例化另一个组件会有什么更好的方法呢?他们的第二段不包括“可能”需要创建的组件将取决于系统状态的情况。或者当组件A需要创建X个组件B时。
答案 0 :(得分:20)
要抽象出另一个组件的实例化,可以使用Factory模式:
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容器中注册实现。
容器是组装对象图的一种方式,但它肯定不是唯一的方法。这是一个实现细节。保持对象不受这些知识的影响将它们与基础设施问题分离开来。它还使他们不必知道要解析的依赖项的哪个版本。
答案 1 :(得分:10)
Autofac实际上对于这种情况实际上有一些特殊功能 - 详细信息在wiki上:http://code.google.com/p/autofac/wiki/DelegateFactories。
实质上,如果A需要创建B的多个实例,则A可以依赖于Func< B>。和Autofac将生成一个从容器中返回新B的实现。
上述其他建议当然有效 - Autofac的方法有两点不同:
希望这有帮助!
尼克
答案 2 :(得分:0)
服务定位器模式更难以测试,并且控制依赖性当然更加困难,这可能导致系统中的耦合比实际需要的更多。
如果你真的想要懒惰的实例化,你仍然可以选择服务定位器样式(它不会立即杀死你,如果你坚持容器的界面,用一些模拟框架测试就不难了)。请记住,尽管在构造函数中没有做太多(或任何事情)的类的实例化非常便宜。
我已经知道的容器(到目前为止不是autofac)将允许您修改应该将哪些依赖项注入到哪个实例中,具体取决于系统的状态,以便即使这些决策也可以外部化到容器的配置中。
这可以为您提供充足的灵活性,而无需根据您在使用依赖项的实例中访问的某些状态来实现与容器的交互。
答案 3 :(得分:0)
IoC负责确定给定对象应使用哪个版本的依赖项。这对于创建实现接口的对象链以及对该接口具有依赖性(类似于命令链或装饰器模式链)的操作非常有用。
通过传递容器,您将把责任放在单个对象上以获得适当的依赖关系,因此它必须知道如何操作。对于典型的IoC使用,对象只需要声明它具有依赖关系,而不是考虑在该依赖关系的多个可用实现之间进行选择。