8

我一直在阅读 Effective Java,我对与 TDD 和依赖注入相关的第一项“使用静态工厂方法而不是构造函数”有一些担忧。

该项目说您应该避免使用公共/受保护/默认构造函数并使用静态工厂公开它。我同意与使用静态工厂相关的所有优点,例如工厂可以有名称、可以返回子类型、可以减少冗长等。但是,我认为 Joshua 错过了 TDD 的缺点,因为在您的代码中使用静态工厂会导致紧密耦合和你不能使用它来模拟类。我们将无法模拟将具有静态工厂的类。因此,它阻碍了测试驱动的开发。

第二点,我认为他错过了在当今的企业开发中,大多数应用程序都使用一个或另一个依赖注入容器。所以,当我们可以使用 DI 注入依赖项时,我为什么要使用它。

请解释它如何应用于当今包括 DI 和 TDD 的 Java 企业开发。

4

3 回答 3

6

DI引擎工厂。

Joshua Bloch 非常了解 DI。我认为这是历史的产物,因为 DI 的崛起是在第一版《Effective Java》之后。

《Effective Java》于 2001 年出版Martin Fowler在 2004 年创造了这个术语。Spring 的 1.0 版本于 2004 年 3 月发布。

Joshua Bloch 没有为第二版修改该章。

关键是“新”引入的耦合。任何了解这一点的人和工厂都将轻松实现向 DI 发动机的飞跃。关键是他关于“新”的说法,以及使用工厂的补救措施,仍然是正确的。

于 2010-06-25T11:23:57.147 回答
4

我在这里看到 2 个单独的问题:

  • 静态工厂与使用 new()
  • 依赖注入

使用 new 时,您的代码与使用静态方法一样紧密耦合,实际上更糟糕的是,静态工厂可以发挥一些作用并返回一些特定的实现,只要它是接口的子类或实现即可。

依赖注入的原则也称为好莱坞原则:“不要打电话给我们,我们会打电话给你”。因此,在该理念中,您不应该在代码中调用 new() 或静态工厂,而是让外部事物为您执行此操作,无论是 DI 框架还是单元测试。这与工厂或使用 new 无关,因为这是在其他地方完成的。

在这种情况下,工厂会更好,因为您可以在您的控制下注入测试工厂。使用 new 这是不可能的(不对类路径做一些奇怪的事情,比如在测试类路径中隐藏带有虚拟对象的实现,我不推荐顺便说一句)。

于 2010-06-25T11:16:26.440 回答
0

我和你有同样的担忧,这就是我发现你的问题的方式。

你说:

因为在你的代码中有静态工厂会导致紧密耦合,你不能使用它来模拟类

这本书建议您应该使用静态方法(api设计)公开您的类的构造函数。它不建议您在整个应用程序中“硬编码”静态调用(api 使用)。

假设您使用 Guice 进行 DI,并且您的接口被称为Connection,您可以这样做:

bind(Connection.class).toInstance(Connections.makeASpecificConnection(params));

然后你平时@Inject Connection connection;

当然,这是如果您的连接是单例的。如果不是这样,您可以注入一个具有创建实例的实现的抽象工厂,该实例调用您的类的静态方法,但这可能有点矫枉过正,您最好单独使用 Guice。

请记住,这本书的主要目标不是构建大型企业应用程序,尽管它仍然非常有用。引用本书序言:

虽然这本书不仅仅针对可重用组件的开发人员,但它不可避免地因我在过去 20 年编写此类组件的经验而受到影响。我自然会想到导出的 API(应用程序编程接口),我鼓励你也这样做。

于 2015-08-06T01:34:20.930 回答