“程序源代码中任何可能表明存在更深层问题的症状。”
在Java中, 静态方法允许您在“类范围”内执行代码,而不是像成员方法这样的实例范围。 这意味着,它们依赖于类级别的变量(如果有),传递给静态方法的参数或任何其他全局可访问的数据。 它们不是面向对象的。 对象具有与之关联的状态,并且只能通过实现该对象“行为”的方法进行操作。 静态方法不在状态上操作,它们不是面向对象的,实际上它们是过程式的。
这不好吗?
不会。尽管Java是面向对象的,但有时还是需要和/或首选Java中的类似于过程的编程。 任何面向对象的语言的真正威力在于能够在代码中紧密实现现实生活中的系统模型的能力(请参阅我有关面向对象建模的文章 )。 但是,即使在最核心的对象模型中,也很可能会有一些粘合代码或将以过程样式实现的基础结构代码。
因此,如果Java中的类似于过程的编程不是“那么糟糕”并且静态方法是过程编程的一种形式,那么静态方法是否不好?
嗯……答案并不像是“是”或“否”那么简单,无论您在其他博客上会读到什么,但我可能会不断争论着为什么这实际上是必须在上下文中做出的决定,因此,让我们重点关注一下我在Michael Minella博客的“如何模拟静态方法”中遇到的一组语句:
“已经成为该语言基础知识的部分(您要做的只是看一下Apache Commons项目以了解这一点)非常糟糕,以测试为名必须不惜一切代价避免。 Gosling(或其团队中的某人)出于某种原因将其放入语言中,并且仅由于您的工具集不支持对它的测试是无稽之谈而避免使用这些语言。 是时候获得新的工具集了。”
首先,我想指出的是,仅仅因为某种东西已经成为一种语言的基本组成部分,并不意味着它就是“好”或应该做的事情。 查看已检查的异常以供参考。 我记得EJB 1.x和2.x在过去成为Java EE的“基础”部分,因此也请参考一下。
其次,尽管我在理论上确实同意Michael的观点,即由于您的工具不支持某种特定的语言功能而使其愚蠢,但他的前提是静态方法。 避免使用静态方法是因为您的工具不支持静态方法,这根本不是胡说。 实际上,由一些好的测试和/或模拟框架( Mockito是我最喜欢的框架)引起的阻抗类型 )和静态方法可以确定地识别为代码异味。 这并不意味着我们不应该这样做,而是应该付出更多的努力来理解我们为什么这样做,并在存在“更深层次的问题”时探索替代方法。
我想指出,至少有两种类型的静态方法通常不会在测试/模拟框架中表现出太大的阻力。 第一种类型是用作实用程序方法的静态方法,就像在许多apache commons库或您自己的内部commons库中找到的方法一样。 这些通常是支持特定方法目标的例程,并且将它们模拟/存根到单元测试之外是没有意义的。 它们是实现的一部分,因此应进行测试。 第二种类型是静态方法,用于代替构造函数,如Joshua Bloch在他的书《 Effective Java》中所展示的。 静态方法的这种使用使您可以使用名称具有非常描述性的方法来构造新对象,以及其他一些优点。 第二种静态方法的分支可能包括工厂方法,但这取决于上下文。
当单元依靠静态方法执行超出该单元职责范围的逻辑时,由于静态方法和测试框架阻抗而产生的最明显的代码异味。 在这些情况下,您的测试框架将对您不利,因为您无法对范围外的逻辑进行存根/模拟,因为它是通过静态方法“硬编码”的。 这可以被视为“更深层的问题”,并且是大多数博客的焦点,这些博客告诉您不要使用静态方法,因为测试变得异常困难或不可能。 更改设计方法以遵循依赖性反转原则是另一种选择。 对如何测试单元的更好的理解是另一个。
我强烈断言,在使用静态方法的情况下,您可能会从测试框架中得到的回退表示代码有气味,而不是您需要尝试找到一个使用复杂的欺骗手段并将类加载器重新映射作为解决方案的框架。 应该准备评估一种特殊方法在其设计中的用途和基本缺陷。 Michael的博客文章使读者太容易采用新的工具/框架,仅因为Java支持静态方法并且您当前的测试框架阐明了一个阻抗-在这种情况下,阻抗反映了代码的味道,需要一些更深入,更批判性的思考。
参考: Java静态方法可能是 JCG合作伙伴 Christian Posta在Christian Posta Software博客上的代码味道 。
翻译自: https://www.javacodegeeks.com/2012/05/java-static-methods-can-be-code-smell.html