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

我问,因为我正在尝试使用一个模拟框架(Mockito),它不允许你模拟静态方法。 调查一下,我发现有不少博客文章说你应该尽可能少的静态方法,但我很难理解为什么。 特别是为什么不修改全局状态的方法基本上是辅助方法。 例如,我有一个名为ApiCaller的类,它有几个静态方法。 静态方法的一个目的是执行HTTP调用,处理我们的服务器可能返回的任何自定义问题(例如用户未登录)并返回响应。 简化,例如:

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

要使用这一切,我所要做的就是调用ApiCaller.makeHttpCall(url)现在我可以很容易地将它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()但这似乎是额外的开销。 任何人都可以解释为什么这是坏的,如果有一个更好的解决方案使方法非静态(除了删除关键字),以便我可以使用模拟框架存根这些方法?

谢谢!

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

     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 

    想象一下,当方法是静态的时,尝试这样做。 除了修改记录器以使用一个名为inTestMode的静态variables(在setUp()设置为true以确保它不连接到数据库setUp()之外,我无法想到一种方法。

    它不那么模块化。 相反,您应该使用实例方法makeHttpCall()定义接口ApiCaller ,以便将来可以定义单独的实现。

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

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

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

    PRIVATE静态辅助方法并不坏,事实上,它们在我工作的大公司中实际上是首选。 我一直使用Mockito,从调用静态辅助方法的方法访问。

    编译器处理静态助手方法的方式略有不同。 创建的字节代码将导致invokestatic指令,如果删除静态,结果将是其他指令之一,如invokespecial。 不同之处在于invokestatic加载类来访问该方法,其中invokespecial首先将对象popup堆栈。 因此可能会有轻微的性能优势(可能不是)。

    当你需要几乎回答你自己的问题时,你不能轻易地嘲笑它们。

    特别是当它显示的内容时:进行HTTP调用是昂贵的,并且对单元测试代码进行这样做是没有意义的 – 除了集成测试。

    unit testing需要来自HTTP调用的已知响应(和响应代码),如果您使用您无法控制的网络调用其他人的服务,则无法执行此操作。