静态工厂和依赖注入

4
在《Effective Java》这本书中,推荐使用静态工厂。
另一方面,推荐保持明确的依赖关系,例如使用 DI(Dependency Injection)。
但是当我想要使用静态工厂时,由于调用静态工厂方法将收到对象实例,因此这种明确性将被跳过。使用静态工厂方法,我不必传递包含静态工厂的对象。
这两个建议如何结合在一起呢?
2个回答

0

非常好的问题。
静态工厂确实有这个缺点(还有其他缺点):它们不是显式的,因此不能用作可切换的依赖项。

我认为你不能将两个东西结合起来使用,因为静态方法与类相关联,而依赖注入与实例相关联。
所以这是一种设计选择。

个人而言,我使用工厂方法,因为我不想允许显式设置工厂返回的依赖项。
这是因为您希望掌握对象的创建:一致性、缓存等,并且您希望提供清晰的API。 这是保证的一种非常直接的方式。
使用依赖注入设置对象将无法提供这种保证。

通常,我为那些既不想提供替代实现也不想在单元测试期间模拟的类执行此操作。
这是业务/模型类的情况,我希望掌握创建过程,也适用于某些“实用”类。
但是,一旦需要显式设置依赖项,我会将静态工厂重构为允许显式设置依赖项的内容。
如果始终需要掌握对象的创建,则将静态工厂转换为我注入的实例工厂。
否则,我直接注入由工厂返回的对象。


那么,如果对于我来说具有可切换的依赖关系更为重要,我应该选择 DI 并省略静态工厂,对吗? - user9195283
这是我会做的事情。你没有其他答案或我的批准,这很烦人。 - davidxxx

0

这个问题有两个方面:

  1. 正在被创建的对象。
  2. 正在进行创建的对象。

工厂、构造函数和自动解析容器是改变对象创建方式(问题2)的手段。这与对象允许自身如何创建(问题1)完全分离。

作为一般性的启发:

  1. 正在被创建的对象在构造时应尽可能灵活,并且应明确地在其构造函数中公布所有依赖项(即使构造函数是私有的,创建者也可以使用工厂)。

  2. 创建者应该与他们所创建的对象尽可能解耦,以保持应用程序的灵活性。高度稳定的依赖关系可以直接依赖。可能会更改或替换的依赖关系则不应该直接依赖。

静态工厂、实例工厂、构造函数和容器自动解析之间的差异主要在于语法。最大的区别在于语义表达(它向开发人员传达了程序结构的信息)和在运行时解决不同实现的能力。

回答你的核心问题,这两个东西可以同时使用,因为它们是解决问题两个独立部分的解决方案。你可以同时使用它们。


你能再具体解释一下吗?我唯一能想象它们如何结合的方式是通过 DI 注入工厂。但实践上编译器不支持这种方式。如果我省略注入,我仍然可以调用静态工厂方法。 - user9195283
不了解您的特定技术栈,很难更具体地说明。在此代码中,我可以使用静态工厂方法在我的容器中注册,如下所示:services.AddScoped(x => Accounts.Create(x.GetService<IEventStore>())); 在这种情况下,Accounts.Create() 将是一个静态工厂方法。 - Silas Reinagel
如果您想获取特定技术栈的详细信息,值得打开一个新问题,并提供导致问题的代码。也许您正在使用注释或类似棘手的Spring框架。大多数自动装配工具都有您可以使用的高级功能。 - Silas Reinagel

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