DI容器:从相同类型的集合中注入正确的组件?

时间:2009-09-07 23:18:09

标签: dependency-injection ioc-container ambiguity

我试图在PHP中破解我自己的依赖注入容器,基于构造函数注入。容器实例化复杂对象,并根据构造函数中使用反射的类型提示为所需对象注入它们。

我明显偶然发现的一件事是,我可以注册多个可以注入的组件,它们具有相同的类型(扩展相同的类/实现相同的接口)。例如,如果两个对象都需要同时实现Iterator接口的不同对象,该怎么办? DI容器通常如何处理这个问题?你如何让容器决定哪些具有模糊接口的对象需要注入哪些复杂对象?

或者只有一个DI容器才能负责创建一种类型的复杂对象?换句话说:对于每个复杂对象,实例化一个不同的DI容器。我很难想象这是意图,对吗?

2 个答案:

答案 0 :(得分:1)

你所描述的不是DI本身,而是自动装配,比普通DI更进一步。通常使用DI,您可以明确地将哪些组件连接到哪些组件。

自动装配DI仅适用于粗粒度组件,其中只有一种合理的给定类型实现(例如DAO)。如果类型不明确,那么您要么将其中一个标记为“主要”,要么将其他标记为“非候选”,或者使用所需组件的名称明确标记该依赖项。

如果有帮助,您可以了解Spring如何处理自动装配herehere

答案 1 :(得分:1)

根据您的问题的含义,这是Guice(Java的DI框架)使用的内容:

如果您每次收到Foo的注入请求时只想要一个不同的对象,那么在连接您的应用程序时,不要将Foo.class绑定到Foo的特定实例,而是绑定Provider<Foo>,这是一个按需创建Foo的对象。然后,注入Foo的每个位置都将获得一个新实例。如果只是将Foo绑定到类而不是Foo实例(例如,Foo是一个接口,并将它绑定到RealFoo.class,这是一个实现{ {1}}),您也可以获得相同的效果 - 每次都会创建一个新实例。 (这是默认的“无范围”行为.Guice范围的行为超出了本评论的范围)

但是,如果您需要在连接应用程序时构建两个Foo实例,然后能够说“在创建Foo或{时使用此Foo实例” {1}},而在制作Bar时会使用另一个实例,您所做的是注释注入点,然后在为应用程序连线时说出如下内容:

Baz

我假设您已经使用以下内容注释Bumble的构造函数的参数:

Foo foo1 = new Foo("1");
Foo foo2 = new Foo("2");
bind(Foo.class).annotatedWith(Names.named("Bar")).toInstance(foo1);
bind(Foo.class).annotatedWith(Names.named("Baz")).toInstance(foo1);
bind(Foo.class).annotatedWith(Names.named("Bumble")).toInstance(foo2);

同样适用于Barpublic Bar(@Named("Bar") Foo foo) { ... 。当然,如果您使用相同的内容注释BazBumble的构造函数,则可以跳过其中一个Bar行。

我知道有基于反射的PHP注释处理框架,或者你可以使用基于参数名称的约定。