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

我问,因为我试图使用一个模拟框架(Mockito),它不允许你嘲笑静态方法。 仔细研究,我发现有不less博客文章说你应该尽可能less的静态方法,但是为什么还要困难呢? 具体来说,为什么不修改全局状态的方法,基本上是辅助方法。 例如,我有一个名为ApiCaller的类,有几个静态方法。 静态方法的一个目的是执行HTTP调用,处理我们的服务器可能返回的任何自定义问题(例如,用户未login)并返回响应。 简化如下:

 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)现在我可以很容易地使这个非静态的方法,如:

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

然后用这个方法调用new ApiCaller().makeHttpCall()但这看起来像额外的开销。 任何人都可以解释为什么这是不好的,如果有一个更好的解决scheme,使非静态方法(除了只是删除关键字),以便我可以用这个模拟框架来剔除这些方法?

谢谢!

Solutions Collecting From Web of "为什么在Java中使用静态帮助器方法不好?"

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

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

connectToDatabaseForAuditing()方法是静态的。 你不关心这个方法对你想写的testing有什么作用。 但是,现在要testing这个代码,你需要一个可用的数据库。

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

 private Logger log; //instantiate in a setter AKA dependency injection/inversion of control public void systemUnderTest() { log.connectToDatabaseForAuditing(); doLogicYouWantToTest(); } 

而你现在的testing对于没有数据库的编写来说是微不足道的:

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

想象一下当方法是静态的时候试图做到这一点。 除了将logging器修改为在setUp()设置为true的静态variables(称为inTestMode setUp()以确保它不连接到数据库之外,我无法真正想到一种方法。

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

至less你总是会有2个接口的实现,原始的和模拟的版本。

(注意:有一些模拟框架允许你模拟静态方法)

作为附录,虽然在您的具体应用中可能不是这种情况,但是通常静态方法的使用表示更大的devise监督。 在整个应用程序中,devise模块化和可重用性应该是普遍的,因为即使你现在不需要它,将来也可能需要它,事后改变事情要困难得多。

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

特别是当它如下所示:进行HTTP调用是很昂贵的,而对于单元testing你的代码是没有意义的,除了集成testing。

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

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

编译器如何处理静态帮助器方法有一点区别。 所创build的字节代码将导致invokestatic指令,如果删除了静态,结果将是其他指令之一,如invokespecial。 不同的是,invokestatic加载类来访问方法,其中invokespecial首先popup对象的堆栈。 所以可能会有轻微的性能优势(可能不会)。