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

在过去十年左右的时间里,我一直在使用下面的模式来实现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; } } 

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

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

基于创建常量接口模式的人反模式,我想说虽然你不打算客户端实现接口,但它仍然可能,可能更容易,并且不应该被允许

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

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


许多易于使用的设计模式受到很多批评(上下文模式,单例模式,常量接口模式)。 哎呀,即使是设计原则,如德米特定律因为过于冗长而受到批评。

我讨厌说出来,但这些决定都是基于意见的。 虽然上下文模式被视为反模式, 但在主流框架(如Spring和Android SDK)中显而易见 。 它归结为环境以及目标受众。

我可以找到的主要缺点是在Constant Interface wiki的 “缺点”下列为第三个列表:

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

如果你曾经想过“嘿,这实际上不是合同而我想加强设计”,你将无法改变它。 但正如我所说,这取决于你; 也许你不会在将来改变它。

最重要的是,@ TagirValeev提到的代码清晰度。 接口的目的是实现; 如果您不希望某人实施您提供的API,请不要使其可实现。 但我相信这围绕着“目标受众”的声明。 不会撒谎,我和你在一个不那么冗长的基础上,但这取决于我的代码是谁; 不希望对可能被审查的代码使用常量接口。

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

关于@ saka1029答案的说明。 虽然你不能在同一个接口中定义辅助私有方法和常量,但在同一个包中创建一个包私有类并不是问题,比如MyInterfaceHelper ,它将包含所有必要的与实现相关的东西。 通常,包私有类可以隐藏外部世界的实现细节。

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

 public class Utility { private Utility() {} public static final Map MAP_CONSTANT; static { Map 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; } } 

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