静态方法是DI反模式吗?

时间:2012-02-20 19:59:32

标签: java dependency-injection mocking static-methods

我是一名开始的Java开发人员,以掌握依赖注入的全部功能,我突然意识到没有办法注入静态方法。所以它让我思考:是静态方法DI反模式?

更重要的是:如果我接受依赖注入,这是否意味着我需要停止编写静态方法?我问,因为在单元测试中无法模仿它们并注入模拟静态,这对我来说是一个巨大的转折。

编辑:我知道“包装”和注入现有静态方法的常用方法是这样的:

public class Foo {
    public static void bar() { ... }
}

public interface FooWrapper {
    public void bar();
}

public class FooWrapperImpl implements FooWrapper {
    public void bar() {
        return Foo.bar();
    }
}

...但我不是在问如何注入一个现有的静态方法...我问我是否应该完全停止写它们,如果我所有的代码(从这一点开始)都要接受这个概念DI。

此外,我看到了许多与此类似的相关问题,但无法找到提出相同问题的完全匹配。如果你发现它确实是另一个问题的愚蠢,请指出我,我将自己关闭这个问题(请不要只是关闭它!)。

3 个答案:

答案 0 :(得分:40)

静态方法适用于没有关联状态的事物。一些工厂方法,像Math.sin这样的“纯功能”方法等都是完全可以接受的静态方法。 java.lang.Mathjava.util.Collections有许多完全可以接受的静态方法的优秀示例。

幸运的是,这些方法不需要依赖注入,也不需要与这些东西进行交互;他们并不难以测试。它们没有需要模拟或其他任何东西的依赖。

另一方面,静态或具有相关静态的静态方法完全是邪恶的。 是一种反模式。

如果且仅当它始终在等效输入上返回等效输出时,将方法定义为非有状态(因此是合法的静态方法)通常会有所帮助。这表明例如数据库查询和文件系统I / O使方法有状态,因为它们的输出将根据文件系统或数据库中的内容而变化。

答案 1 :(得分:3)

非平凡的静态方法 与依赖注入兼容。简单地将它们作为单例的实例方法。

答案 2 :(得分:-1)

我将您的问题重新表述为“当我使用依赖注入时,如何区分 java 方法什么时候应该是静态的,什么时候不应该是静态的?”

在我看来,区分不应该纯粹基于是否有状态,而应该基于您是否想在测试中模拟该方法。 我知道像 Mockito 这样较新的 BDD 测试框架完全能够模拟静态方法,但这样做会带来显着的性能成本。