在抽象类中暴露静态方法是否被视为良好或不良实践?

5

我最近看到一些代码,其中在抽象类中定义了一个公共静态方法。我想知道这是否被认为是良好的实践还是反模式?

我编写了一个简单的示例程序来说明我的意思。

public abstract class StaticMethodsInAbstractClassesStudy {

    public static int adder(int a, int b){
        return a + b;
    }

}

public class StaticMethodsInClassesStudy {

    public static void main(String [] args){

        System.out.println(StaticMethodsInAbstractClassesStudy.adder(2, 3));

    }
}

运行代码后,你会得到5的结果,这证明我能够在抽象类中运行代码。
故意没有向StaticMethodsInClassesStudy添加extends,以强调可以直接在抽象类中运行代码而无需实例化扩展类。
个人认为这是一种不好的实践,因为你正在将一个抽象类用作普通类,从而绕过抽象类意图。这些方法应该放在单独的“普通”Java类中,例如实用程序类。

如果您从未打算实例化“StaticMethodsInAbstractClassesStudy”(也就是说,没有使用“StaticMethodsInAbstractClassesStudy”的实例),那么它就没有必要是抽象的。将其设置为一个带有私有构造函数的最终类。 - Andy Turner
1
请定义“良好实践”和“不良实践”。这些只是意见。 - jaco0646
这真的取决于所涉及的方法,静态通常被初学编程的人滥用作为字段/方法访问的临时解决方案。一般来说,只要静态方法在使用中不会修改某些内部(和静态)状态,那么通常将其设置为静态是可以接受的。总体而言,这取决于你正在设计什么。 - Rogue
1
另一个需要考虑的问题是:static 方法不会被继承,因此不能被子类重写。如果您打算让它被重写,则不能使用 static,如果您不希望它被重写,则 finalstatic 更明确地实现了这一点。 - JonK
当然可以在抽象类中运行代码。您只是无法实例化它们。一个静态初始化器将是另一种方法来演示它,而不需要子类化或以其他方式干扰您的示例。 - Kayaman
有些人(甚至很多人)认为涉及“静态”的事情是“不好的”。这并不是真的。(有人抱怨java.lang.Math吗?)静态方法本质上是无状态的,因此是纯函数式的(如果不是这样,也就是说,当涉及到静态字段时,那么几乎总是糟糕的...)。在一个abstract类中拥有一个public static方法可能有点不寻常,但仍然可能存在正当的情况。相关的,参考protected abstract:https://dev59.com/_mAf5IYBdhLWcg3wyVB1 - Marco13
2个回答

2

本身来说,这并不是不良做法,除非抽象类实际上并不打算作为子类的父类,而且抽象只是为了防止实例化。对于提供仅静态工具的类而言,最佳做法是将其设置为final,并拥有一个私有构造函数。


@bowmore,在我看来,这样做会像使用抽象类防止实例化一样滥用(甚至更加严重)。枚举应该具有枚举值。它具有valueOf()方法、values()方法等,这些都不应该是实用程序类的一部分。 - JB Nizet
嗯,我会说,如果你只提供静态实用程序的类,那么你已经抛弃了最佳实践 :) - bowmore
@bowmore 嗯,不是的。在静态实用程序和工厂方法方面,这是相当普遍和正常的。可以看看java.util.Collections、SwingUtilities、Guava的Maps、Lists、Sets等。 - JB Nizet
通常使用并不意味着最佳实践。工厂方法当然是一个很好的静态方法的应用,但我无法理解为什么这些需要分组在一个无法实例化的单独类中。其他类型的静态方法,存放在一个无法实例化的类中,只会促进强耦合。本质上,它遭受了许多与 singleton 相同的问题。此外,例如在 Collections 中,你会发现许多方法,如 max、reverse、rotate、shuffle 等,这些显然闻起来像是 feature envy(特性嫉妒)。SwingUtilities 也是一样。 - bowmore
@JBNizet 谢谢您的回答 - 当您说“提供仅静态实用程序的类的最佳做法是使其final,并具有私有构造函数”时,您不会添加这应该在普通类中而不是抽象类中吗?当抽象类的意图是它不可“实例化”并且只能从中继承时,在抽象类中运行方法肯定是不正确的。事实上,我可能会进一步建议这是语言中的一个缺陷,即这甚至是可能的。 - robbie70
显示剩余6条评论

0

我同意你的观点,抽象类让我们想到一些在实例化之前不使用的东西。

在抽象类中插入一些支持方法是允许且有用的,而不需要强制开发人员实现该类。

此外,在一个接口中,您可以放置静态方法,并且可以在不实现该接口的情况下使用它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接