26

在过去十年左右的时间里,我一直在为我的 Java 实用程序类使用下面的模式。该类仅包含静态方法和字段,已声明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 在接口中引入静态方法,我最近发现自己在使用实用程序接口模式:

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

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

        return null;
    }
}

这使我可以摆脱构造函数以及接口中隐含的许多关键字( public, static, )。final

这种方法有什么缺点吗?使用实用程序类而不是实用程序接口有什么好处?

4

4 回答 4

11

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

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

于 2015-06-18T02:41:36.157 回答
5

基于将常量接口模式创造为反模式的人,我想说尽管您不打算让客户端实现接口,但它仍然是可能的,可能更容易,并且不应该被允许

API 应该易于使用且难以误用。做简单的事情应该很容易;可以做复杂的事情;做错事是不可能的,或者至少是困难的。

虽然如下所述,但它确实取决于目标受众


许多易于使用的设计模式受到了很多批评(上下文模式、单例模式、常量接口模式)。哎呀,即使是诸如得墨忒耳法则之类的设计原则也因过于冗长而受到批评。

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

我能找到的主要缺点列在Constant Interface wiki中“缺点”下的第三个列表中:

如果在将来的版本中需要二进制代码兼容性,则常量接口必须永远保持为接口(它不能转换为类),即使它没有被用作传统意义上的接口。

如果您曾经想过“嘿,这实际上不是合同,我想强制执行更强大的设计”,您将无法更改它。但正如我所说,这取决于你;也许您将来不会在意​​更改它。

最重要的是,@TagirValeev 提到的代码清晰。接口具有被实现的意图;如果您不希望有人实现您提供的 API,请不要使其可实现。但我相信这围绕着“目标受众”的说法。不会撒谎,我支持你的基础不那么冗长,但这取决于我的代码是为谁服务的;不想为可能会被审查的代码使用常量接口。

于 2015-06-18T04:05:35.127 回答
2

你不应该使用界面。接口不能有私有常量和静态初始化器。

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;
    }
}
于 2015-06-18T02:21:37.107 回答
0

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

于 2015-06-18T02:02:47.707 回答