接口是 Java 8 中实用程序 类 的有效替代品吗?

Are interfaces a valid substitute for utility classes in Java 8?

在过去十年左右的时间里,我一直在为我的 Java 实用程序 classes 使用下面的模式。 class 仅包含静态方法和字段,声明为 final 因此无法扩展,并且具有 private 构造函数因此无法实例化。

public final class SomeUtilityClass {
    public static final String SOME_CONSTANT = "Some constant";

    private SomeUtilityClass() {}

    public static Object someUtilityMethod(Object someParameter) {
        /* ... */

        return null;
    }
}

现在,随着 Java 8 中 static methods in interfaces 的引入,我最近发现自己在使用实用程序界面模式:

public interface SomeUtilityInterface {
    String SOME_CONSTANT = "Some constant";

    static Object someUtilityMethod(Object someParameter) {
        /* ... */

        return null;
    }
}

这让我摆脱了构造函数,以及接口中隐含的许多关键字(publicstaticfinal)。

这种方法有什么缺点吗?在实用程序界面上使用实用程序 class 有什么好处吗?

我认为它会起作用。我认为变量 SOME_CONSTANT 在您的 SomeUtilityInterface 中默认为 static final,即使您没有明确这么说。因此,它可以作为一个实用程序使用,但是您是否会遇到一些可变性问题,而常规 class 不会有一些可变性问题,并且所有成员变量都必须是最终变量?只要这不是您对默认方法的特定实现的问题,我想不出问题。

你不应该使用界面。 接口不能有私有常量和静态初始值设定项。

public class Utility {

    private Utility() {}

    public static final Map<String, Integer> MAP_CONSTANT;
    static {
        Map<String, Integer> map = new HashMap<>();
        map.put("zero", 0);
        map.put("one", 1);
        map.put("three", 3);
        MAP_CONSTANT = Collections.unmodifiableMap(map);
    }

    private static String PRIVATE_CONSTANT = "Hello, ";

    public static String hello(String name) {
        return PRIVATE_CONSTANT + name;
    }
}

只有当您希望有人会实现它时,您才应该使用接口。例如,java.util.stream.Stream 接口有一堆静态方法,这些方法可能位于 StreamsStreamUtils class 之前 Java 8。但是它是有效的接口也具有非静态方法并且可以实现。 java.util.Comparable 是另一个例子:那里的所有静态方法都只支持接口。您不能禁止用户实现您的 public 接口,但对于实用程序 class 您可以禁止他们实例化它。因此,为了代码清晰,我建议不要使用接口,除非它们旨在实现。

关于@saka1029 回答的注释。虽然你不能在同一个接口中定义辅助私有方法和常量,但在像 MyInterfaceHelper 这样的同一个包中创建一个包私有 class 并不是问题,它将具有所有必要的实现 -相关的东西。一般来说,package-private classes 可以很好地向外界隐藏您的实现细节。

根据创造常量接口模式的人的反模式,我会说虽然你不打算让客户端实现接口,但它仍然是可能的,可能更容易,并且 不应该被允许:

APIs should be easy to use and hard to misuse. It should be easy to do simple things; possible to do complex things; and impossible, or at least difficult, to do wrong things.

尽管如下所述,但这确实取决于目标受众


许多易于使用的设计模式受到了很多批评(上下文模式、单例模式、常量接口模式)。哎呀,甚至像得墨忒耳法则这样的设计原则也因为过于冗长而受到批评。

我不想这么说,但这些决定都是基于意见的。尽管上下文模式被视为一种反模式,它在主流框架中很明显,例如 Spring 和 Android SDK。它归结为环境,以及目标受众。

我能找到的主要缺点 被列为 Constant Interface wiki 中 "downsides" 下的第三个清单:

If binary code compatibility is required in future releases, the constants interface must remain forever an interface (it cannot be converted into a class), even though it has not been used as an interface in the conventional sense.

如果您曾经想过 "Hey, this actually isn't a contract and I want to enforce stronger design",您将无法更改它。但正如我所说,这取决于你;也许您将来不会在意​​更改它。

最重要的是,@TagirValeev 提到的代码清晰度。接口有被实现的意图;如果您不希望有人实施您提供的 API,请不要使其可实施。但我相信这围绕着 "target audience" 声明。不会说谎,我在不那么冗长的基础上支持你,但这取决于我的代码是为谁准备的;不想为可能会被审查的代码使用常量接口。