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

接口是Java8中实用程序类的有效替代品吗?,java,class,interface,java-8,utility-method,Java,Class,Interface,Java 8,Utility Method,在过去十年左右的时间里,我一直在为我的Java实用程序类使用下面的模式。该类只包含静态方法和字段,被声明为final,因此无法扩展,并且具有private构造函数,因此无法实例化 public final class SomeUtilityClass { public static final String SOME_CONSTANT = "Some constant"; private SomeUtilityClass() {} public static Obje

在过去十年左右的时间里,我一直在为我的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


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

我认为它会起作用。我认为变量SOME_常量在SomeUtilityInterface中默认为静态final,即使您没有明确地这样说。所以,它可以作为一个实用程序工作,但您是否会遇到一些可变性问题,而对于所有成员变量都必须是final的常规类,您不会遇到这些问题?只要默认方法的特定实现没有问题,我想不出有什么问题。

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

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;
    }
}
公共类实用程序{
专用实用工具(){}
公共静态最终Map_常量;
静止的{
Map Map=newhashmap();
map.put(“零”,0);
地图.放("一",一);;
地图放置(“三”,3);
MAP_常量=集合。不可修改的映射(MAP);
}
私有静态字符串private_CONSTANT=“Hello,”;
公共静态字符串hello(字符串名称){
返回私有_常量+名称;
}
}

只有当您希望有人实现它时,才应该使用接口。例如,
java.util.stream.stream
接口有一组静态方法,这些方法可能位于java 8之前的一些
StreamUtils
类中。然而,它是一个有效的接口,也有非静态方法
java.util.Comparable
是另一个例子:那里的所有静态方法都只支持接口。你不能禁止用户实现你的公共接口,但对于实用类,你可以禁止他们实例化它。因此,为了代码清晰,我建议不要使用接口,除非它们是有意的执行


关于@saka1029答案的说明。虽然不能在同一个接口中定义助手私有方法和常量,但在同一个包中创建包私有类(如
MyInterfaceHelper
)并没有问题,它将包含所有必要的实现相关内容。通常包私有类是很好地向外部世界隐藏您的实现细节。

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

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

尽管如下文所述,这实际上取决于目标受众


很多易于使用的设计模式都受到了很多批评(上下文模式、单例模式、常量接口模式)。见鬼,即使是demeter法则等设计原则也因过于冗长而受到批评

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

我能找到的主要不利因素列为以下列表中“不利因素”下的第三项:

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

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


最重要的是,@TagirValeev.Interfaces提到的代码清晰性。接口有实现的意图;如果您不希望有人实现您提供的API,请不要使其可实现。但我相信这与“目标受众”有关声明,不说谎,我与你在不太冗长的基础上,但这取决于我的代码是谁;不想使用一个恒定的接口,为代码可能得到审查。< / P>它肯定是有效的。接口字段是隐式的<代码>公共< /代码>,<代码>静态< /代码>和<代码>最终< /代码>,所以我不认为有任何突变。属性问题。通常只能在构造函数权限中修改最终成员(不能在包含方法中修改)?因此,也许可以在实现类的构造函数中设置它们?您尝试过了吗?最终成员可以在声明或构造函数中初始化,但它们只能初始化一次。由于默认情况下接口中的字段是
public static Final
,并且它们已在声明中初始化,我不知道ee你所描述的是如何实现的。是的,我认为这不是一个好主意。我通常使用Spring自动连接实用程序类和实例成员,因此作为一个常规类来实现它确实很好。@SotiriosDelimanolis:它将类的实现细节放入类的公共API中。我相信静态重要性的具体原因之一是rts的存在是为了让人们不那么倾向于这样做