依赖注入中使用抽象工厂模式?

50

我决定在一个大项目中使用IoC原则。然而,有一件事情一直困扰着我。我的结论是,IoC容器是一种架构模式,而不是设计模式。换句话说,没有任何类应该知道它的存在,容器本身应该在应用程序层使用,将所有组件连接起来。基本上,它成为了一个选项,在一个良好设计的面向对象模型之上。

话虽如此,如何在不到处使用IoC容器的情况下访问已解析的类型(无论它们是否被抽象)?我唯一看到的选择是利用抽象工厂使用IoC容器来解析具体类型。这应该很容易地替换为一组标准工厂。这是一个好方法吗?有人在这里用过它吗?它的效果如何?还有其他可用的方法吗?

谢谢!

2个回答

72

正如你已经了解的那样,依赖注入(DI)本身只是一组模式和技术。

在应用程序的根上,我们连接所有必要的对象图。这个地方被称为Composition Root,我们可以使用 DI 容器为我们进行这种连接,或者我们可以手动进行(Pure DI)。

重点是,在你的应用程序中只有一个地方有对特定技术的强引用(你的 DI 容器)。应用程序的其余部分完全不知道对象图是如何连接的 - 所有需要的依赖关系都得到了正确的注入(你可以使用构造函数注入空值守卫来保证这一点)。

抽象工厂模式在 DI 中非常有用。实质上,当以下情况之一发生时,请使用抽象工厂:

  • 在解决依赖关系之前,您需要提供一个或多个仅在运行时已知的参数。
  • 依赖关系的生命周期在概念上比消费者的生命周期更短。

有关示例和更多信息,请访问此处:


1
我觉得我快要完成了。请跟着我 :) 假设我有一个IFruit接口,由Apple类实现。在注册这个具体类型之后,我想在Windows表单中的按钮单击事件中使用它。如何在不显式访问IoC容器的情况下获取到Apple类? - Sergey
7
这要看你的应用程序中有许多IFruit实例还是只有一个。如果只有一个,它应该已经被注入到处理按钮点击的类中。如果有多个,则很可能需要一个IFruitFactory,可以从其他运行时值创建IFruit实例。在后一种情况下,IFruitFactory将是被注入的依赖项。 - Mark Seemann
只考虑存在一个IFruit实例,我认为它被注入到Form类中的按钮点击事件的唯一方法是,如果我更改表单构造函数以包括IFruit接口,然后将表单本身注册到IoC容器以执行构造函数注入。这听起来正确吗?感谢您的帮助! - Sergey
IoC容器(如CDI、Spring、Guice等)如果您仔细查看,您会发现IoC看起来与抽象工厂完全相同。调用_container.getBeanForType(BeanType.class)_我们正在执行创建过程,而不需要了解如何在给定平台上创建具体对象。所提到的平台由一组所有可注入的bean(条件bean、配置文件、在执行更复杂条件的代码中动态创建的bean等)定义。 - rzur2004
工厂的具体实现是否应该访问IOC容器接口,以便向工厂返回请求的特定接口的正确实例? - tonix
显示剩余3条评论

4

在你的应用程序的最顶层,你需要一个加载IOC上下文的Bootstrap类。这个上下文将提供实际实例化的对象,因此充当工厂。

但是,这只应该发生在非常少量的对象上,你的Bootstrap/Factory类的用户应尽可能少地了解底层架构。例如,如果你完全通过IOC配置了HTTP服务器对象,并且想要启动它,你的Bootstrap类只需要提供一个getHttpServer()方法。然后,你的程序主方法只需要调用Bootstrap.getHttpServer().start()即可让它运行。

其他对象的连接已经由应用程序上下文完成了,例如,你通过IOC配置了对象A,它是对象B的一部分,因此你使用对对象A的引用来配置对象B。它们通常都不需要知道容器或工厂的任何信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接