为什么在Java中使用静态帮助器方法不好?

我问是因为我试图使用一个模拟框架(Mockito),它不允许你模拟静态方法。在研究它时,我发现很多博客文章说你应该尽可能少的静态方法,但我很难理解为什么。具体来说,为什么不修改全局状态的方法基本上是帮助器方法。例如,我有一个名为具有多个静态方法的类。静态方法的目的之一是执行HTTP调用,处理服务器可能返回的任何自定义问题(例如,用户未登录)并返回响应。为了简化,像这样:ApiCaller

public class ApiCaller {
...
   public static String makeHttpCall(Url url) {
        // Performs logic to retrieve response and deal with custom server errors
        ...
        return response;
   }
}

要使用它,我所要做的就是调用Now,我可以很容易地使它成为一个非静态方法,例如:ApiCaller.makeHttpCall(url)

public class ApiCaller {
...
   public String makeHttpCall(Url url) {
        // Performs logic to retrieve response and deal with custom server errors
        ...
        return response;
   }
}

然后使用此方法调用,但这似乎只是额外的开销。任何人都可以解释为什么这很糟糕,如果有更好的解决方案使这些方法非静态(除了删除关键字),以便我可以使用模拟框架来存根这些方法?new ApiCaller().makeHttpCall()

谢谢!


答案 1

静态方法的问题在于,当它们与您尝试测试的系统无关时,它们很难伪造。想象一下这段代码:

public void systemUnderTest() {
    Log.connectToDatabaseForAuditing();
    doLogicYouWantToTest();
}

该方法是静态的。您不在乎此方法对要编写的测试的作用。但是,要测试此代码,现在您需要一个可用的数据库。connectToDatabaseForAuditing()

如果它不是静态的,代码将如下所示:

private Logger log; //instantiate in a setter AKA dependency injection/inversion of control

public void systemUnderTest() {
    log.connectToDatabaseForAuditing();
    doLogicYouWantToTest();
}

现在,如果没有数据库,您的测试编写起来将是微不足道的:

@Before
public void setUp() {
    YourClass yourClass = new YourClass();
    yourClass.setLog(new NoOpLogger());

}

//.. your tests

想象一下,当方法是静态的时,尝试这样做。我真的想不出一种方法,除了修改记录器以使用一个名为的静态变量,您可以在中将其设置为true,以确保它不会连接到数据库。inTestModesetUp()


答案 2

它的模块化程度较低。相反,您应该使用实例方法定义一个接口,以便将来可以定义单独的实现。ApiCallermakeHttpCall()

至少,您将始终拥有2个接口实现,原始版本和模拟版本。

(注意:有一些模拟框架可以让你模拟静态方法)

作为附录,虽然在您的特定应用程序中可能不是这种情况,但通常使用静态方法表明存在更大的设计疏忽。模块化和可重用性设计应该在整个应用程序中都很普遍,因为即使您现在不需要它,将来也可能需要它,而且在事后进行更改要困难得多,也要耗时得多。


推荐