2015-10-18 76 views
0

我可以在层次结构中使用DI容器创建新对象吗?为每个DI容器设置依赖关系,然后按类型声明getInstance,并正确创建实例。另外,你可以阅读很多文章,解释DI容器应该位于主函数的层次结构的顶部,它不应该被传递或单独传递。但是如果我想从容器中的实例从对象的层次结构中下来呢?我可以在层次结构中使用DI容器吗?

+0

请提供一些伪代码。它很难理解你的意思是什么样的层次结构:call,object,type,context? – Basilevs

+0

*我可以在层次结构中使用DI容器吗?*您可以,但[您不应该](http://stackoverflow.com/a/2386636/126014)。 –

+0

*如果我想从容器中的实例从对象的层次结构中获取实例?*为什么要这么做?什么是用例? –

回答

1

避免让应用程序代码(启动代码除外)直接依赖容器或对容器的抽象;这是一种反模式,称为Service Locator。启动代码通常被称为Composition Root

组合根是在您的应用程序中单独的。该层位于其他层之上,例如表示层和业务层。

但这并不意味着您不能使用容器在某种情况之后以懒惰的方式创建对象图的某些部分。这里有一个例子:

// Defined in a shared library of your application, accessible to all other 
// code in your application. 
public interface ICommandProcessor 
{ 
    public void Process(object command); 
} 

这个接口的可能的用法如下:

this.commandProcessor.Process(new ShipOrderCommand(orderId)); 

虽然抽象并没有注意一下使用的可能容器的话,这个抽象的实现仍可以取决于一个。但是由于应用程序代码不应该依赖容器,因此应该在Composition Root(应用程序的启动路径)中定义此实现。这允许应用程序保持对这种工具的存在的遗忘,而容器仍然可以用于解析对象图。下面是一个示例实现:

public class CommandProcessor : ICommandProcessor 
{ 
    private readonly Container container; 
    public CommandProcessor(Container container) { 
     this.container = container; 
    } 
    public void Process(object command) { 
     Type handlerType = typeof(ICommandHandler<>).MakeGenericType(command.GetType()); 
     dynamic handler = this.container.GetInstance(handlerType); 
     handler.Handle((dynamic)command); 
    } 
} 

所以长话短说,你可以使用容器延迟的方式创建对象图,只要在你的应用程序,使用集装箱的唯一层是构图的根。

+0

你说的**应用程序代码本身不必调用GetInstance **?如何定义应用程序代码,以及为什么'CommandProcessor'类的Process'方法不被视为应用程序代码? – Narek

+0

@Narek:虽然Composition Root是您为应用程序编写的代码的patt,但我们认为它有点不同,并经常谈论Composition Root与其他应用程序。虽然CR可能取决于Container,但您的应用程序的其余部分可能不会。 – Steven

+0

听起来像'Process'方法**是应用程序的其余部分**,对不对?所以看起来,你说应用程序代码不应该使用,但是你在应用程序代码中使用它。 – Narek