IoC和动态对象

时间:2009-04-28 08:02:36

标签: dependency-injection inversion-of-control

我无法弄清楚如何解析依赖于在运行时非确定性创建的对象的对象。什么是最好的方法?

想象一下像文字处理器这样的东西。对于打开的每个文档,您可能希望创建大量依赖于文档对象的对象。

例如,您希望获得DocumentEditor的实例:

public class DocumentEditor {
    public DocumentEditor(IDocument document, 
                          ISpellChecker spellChecker, 
                          IWordCounter wordCounter) {
        ...
    }
}

到目前为止,我已经考虑了两种方法,但似乎都不合适:

使用注入的工厂

这种方法的问题在于,您最终可能需要为每种类型创建工厂。即。

public interface ISpellCheckerFactory {
    ISpellChecker Create(IDocument document);
}

public interface IWordCounterFactory {
    IWordCounter Create(IDocument document);
}

public class DocumentEditorFactory {
    public DocumentEditorFactory(ISpellCheckerFactory spellCheckerFactory,
                                 IWordCounterFactory wordCounterFactory) {
        ...
    }

    public DocumentEditor Create(IDocument document) {
        ...
    }
}

添加另外50个课程,你会看到问题......

使用嵌套容器

使用嵌套容器无需创建数百个工厂。它实际上非常紧凑(使用Unity的例子):

var child = container.CreateChildContainer();
child.RegisterInstance<IDocument>(theDocument);
child.Resolve<DocumentEditor>();

这种方法的缺点是容器在整个地方都会泄漏。

(作为旁注,统一实施这有点棘手。例如:见How to register types in the main container, but resolve in a child container?

混合方法

应该可以通过实现创建嵌套容器的DocumentEditorFactory并使用子容器来解析依赖关系来组合这两者。

分析瘫痪最好......

4 个答案:

答案 0 :(得分:1)

在autofac中有一种名为DelegateFactories的方法。它有点类似于你的第一个选项,但删除了大量的手工编码。

答案 1 :(得分:0)

我建议您尝试AutoFac,因为它在这些跟踪问题上非常成熟。您将服务注册到ContainerBuilder,并且您构建的容器会根据其范围跟踪您请求的对象。标记为ContainerScoped的每个对象将在处置容器时处理。因此,您可以为每个DocumentEditor创建一个容器,并在不再需要文档时配置容器。

http://code.google.com/p/autofac/wiki/NuancesOfTracking

答案 2 :(得分:0)

  

使用注入的工厂

     

这种方法的问题在于   你最终可以找到一个工厂   你需要创建的类型。

这是关于依赖注入的常见神话。 I highly recommend Misko Hevery's article regarding the new operator。简而言之:您只需要为每个生命周期创建一个工厂,而不是为每种类型创建一个工厂。

答案 3 :(得分:-1)

尝试MEFy方法:您可以将所有SpellCheckerWordCounter作为所谓的扩展,实现说IDocumentEditorExtension接口并在运行时查询(伪代码):

IDocumentEditor editor = Registry.Resolve<IDocumentEditor>();
IDocumentEditorExtension[] extensions = Registry.ResolveAll<IDocumentEditorExtension>();

extensions.ForEach((e) => e.AttachTo(editor));