应该将一组常量放在类或接口中吗?

时间:2009-09-03 11:59:53

标签: java standards coding-style

如果我有一组静态常量,我想集中声明这些静态常量,以便它们可以在各种项目中共享,如果它们放在类或接口(Java)中。

过去我看过它们大多放在一个类中,但我开始认为,因为类不会也不应该被实例化,也许它们在接口中会更好,但是接口再也不应该由任何实现课程,例如

public class ErrorCodes {
    public static final String ERROR_1 = "-1";
    public static final String ERROR_2 = "-2";
}

public interface ErrorCodes {
    public static final String ERROR_1 = "-1";
    public static final String ERROR_2 = "-2";
}

10 个答案:

答案 0 :(得分:31)

如果他们有很强的联系,那么我会把它们放在枚举中:

public enum Error {
  ERROR_1("-1", "foo went wrong"),
  ERROR_2("-2", "bar went wrong");

  private final String id;
  private final String message;

  Error(String id, String message) {
    this.id=id;
    this.message=message;
  }

  public String getId() {
    return id;
  }

  public String getMessage() {
    return message;
  }
}

优点是您可以在代码中使用类型安全性,并且可以轻松添加基于id的查找(通过在构造函数中构建HashMap<String,Error>或简单地循环遍历values())。

答案 1 :(得分:10)

有些人认为常规接口是反模式(http://en.wikipedia.org/wiki/Constant_interface)。

答案 2 :(得分:6)

你应该在课堂上做。

接口是类用户可以访问的可用方法,属性等的描述 - 通过实现接口,您可以保证在接口中声明的成员对用户可用。

另一方面,一个类是一个对象的描述,或者(如果你在OO原则上那么难......)一个静态成员的占位符。我个人发现在一些项目中将一堆常量存储在Settings类中非常有用,所以我不必在整个项目中查看定义。我认为这种方法也是你所追求的。

答案 3 :(得分:6)

已经讨论过before

  

您不希望接口中存在常量的原因是它诱使客户端类“实现”该接口(为了访问常量而不使用接口名称作为前缀)。但是,您不应该 - 接口实际上不是对象功能的接口,而是在类外部类型中根深蒂固的编译时方便性。

曾经有一段时间“常量界面”非常方便,但它一直是“错误的”,即使懒惰也是使用它的借口,因为我们有import static语句。

编辑虽然我必须同意,对于您问题中提供的方案,枚举更合适。

答案 4 :(得分:5)

此处应考虑使用 static import (用于导入类中定义的常量)或type-safe Enum

来自Interface for constants

  

在Java的早期,将常量​​放在接口中是一种流行的技术,但现在很多人认为它是一种令人讨厌的接口使用,因为接口应该处理对象提供的服务,而不是它的数据
  同样,类使用的常量通常是实现细节,但将它们放在接口中会将它们提升为类的公共API。

答案 5 :(得分:2)

你应该把它们放在带有私有构造函数的类上。

public class ErrorCodes {
    private ErrorCodes() {} // prevents instantiation
    public static final String ERROR_1 = "-1";
    public static final String ERROR_2 = "-2";

}

或者更好的是,使用类型安全的枚举。

答案 6 :(得分:2)

我建议静态导入和常量接口的组合。

如果Java接口具有常量字段声明,请记住这些是隐式 public,static和final(请参阅Java语言规范,Section 9.3。)因此,您可以始终省略这些修饰符只留下类型,而你的常量接口看起来像这样:

public interface Constants {
    int AGE = 0x23;
    String NAME = "Andrew";
    boolean IGNORE = true;
}

当然,这应该 只能使用如下:

import static Constants.*;

public Whatever {
    public String method() {
        return String.format("%s is %d%c", NAME, AGE, IGNORE ? '?' : '!');
    }
}

我在生产代码中使用这种风格没有任何问题,并且感觉它会导致一个非常整洁,紧凑的常量集合,并且可以处理各种类型的常量,这是枚举不可能的,并且能够如果需要,可以延长,不像枚举。

另一种不是每个人都会赞同的可能性是在父接口中嵌套接口(甚至是枚举类型),允许您对常量进行分组。这个:

interface MoreConstants {
    int MAGIC = 0xCAFEBABE;
    interface PROPERTIES {
        String NAME = "name";
    }
    enum ERRORS {
        ON_FIRE, ASLEEP, BROKEN, UNSURE;
    }
}
假设静态导入 MoreConstants 接口,

并像这样访问它们:

if (!PROPERTIES.NAME.equals(value)) {
    return ERRORS.UNSURE;
}

当然,永远不应该实现这些接口,我认为这是不好的做法。然而,确保这一点的唯一方法是严格的代码审查......

答案 7 :(得分:0)

我个人觉得应该在类中定义常量,原因与上面描述的相同。特别是因为一些开发人员通过在想要使用它们的类中实现接口来使用这些常量。当该接口包含许多常量时,您不再需要查看该特定类的javadoc,因为它中充斥着可能甚至不被该类使用的常量的描述。

答案 8 :(得分:0)

使用接口作为常量是一种很好的做法。但是您不希望实现该接口以使用常量。但是如下所示使用静态导入。

package com.data.job.spark;

public interface Constants {

    /** base api url string literal. */
    public static final String BASE_API_URL = "/api/v1";
        /** message string literal. */
    public static final String MESSAGE = "message";

    /** exception string literal. */
    public static final String EXCEPTION = "exception";
}
=================================
import static com.data.job.spark.Constants.EXCEPTION;

@Component("user360ToScyllaDbLoader")
public class TestConstants implements Serializable{


    private static final long serialVersionUID = 1L;
}

答案 9 :(得分:0)

始终仅使用Interface来定义协定,而使用Class来定义实现状态(变量和常量)和行为(方法实现)

Define Constants in Interface or Class

阅读这篇文章,解释在类vs接口中定义常量的优点