在Java中定义常量的位置问题在论坛中出现过很多次,但我很难找到一个我觉得舒服的解决方案。
为简单起见,假设我有两个类:WriteMyData
和ReadMyData
。 None是另一个的子类。这两个类共享两个对其操作至关重要的常量:String DELIMITER
和int LENGTH
。将来我可能想要更改这些常量的值,以便在适当的地方定义它们。
共识似乎常常偏向enum
类型。但是,在我的情况下,枚举没有任何内容,因此我的enum
中只有一个项目,我称之为DEFAULT
:
public enum DataSettings {
DEFAULT(",", 32);
private final String delimiter;
private final int length;
DataSettings(String delmiter, int length) {
this.delimiter = delimiter;
this.length = length;
}
public String getDelimiter() { return delimiter; }
public int getLength() { return length; }
}
因此,在我的两个类中,我通过DataSettings.DEFAULT.getDelimiter()
和DataSettings.DEFAULT.getLength()
访问常量。
这是非常好的OO风格吗? enum
的使用是否过度杀伤?如果我不使用enum
,我该怎么做呢?为常量创建一个接口似乎不受欢迎,而且我的类似乎没有自然的超类来源。在enum
中只有一个默认项是初学者错误吗?
答案 0 :(得分:3)
只需创建类似was_gifted()
类的内容,您将放置所有常量。
例如:
Constants.java
并按照您的意愿使用它们:
public class Constants {
public static final String DELIMITER = "-";
public static final int LENGTH = 1;
}
答案 1 :(得分:2)
如果只有那两个constans并且不会有更多,你可以有一个像
这样的界面interface DataSetting
{
String DELIMITER = ",";
int LENGTH = 32;
}
如果你需要通过属性启动
public class DataSetting {
public static String DELIMITER = ",";
public static int LENGTH = 32;
static {
DELIMITER = System.getProperty("delimiter");
LENGTH = Integer.parseInt(System.getProperty("length"));
// or from config
}
}
答案 2 :(得分:1)
当没有任何可以枚举的内容时使用enum
确实是不好的做法。
另一个提到的替代方案,使用interface
也是一个糟糕的选择。有效的Java,第19项最好地描述了它:
第19项:仅使用界面来定义类型
当类实现接口时,接口用作类型,可用于引用类的实例。因此,类实现接口应该说明客户端可以对类的实例做什么。为任何其他目的定义接口是不合适的。
一种未通过此测试的接口是所谓的常量接口。这样的接口不包含任何方法;它仅由静态最终字段组成,每个字段都输出一个常量。使用这些常量的类实现接口,以避免使用类名限定常量名称。
正确的实现是定义一个不可实例化的实用程序类:
public class Constants {
private Constants(){} // Private constructor prevents instantiation AND subclassing
public static final String DELIMITER = "-";
public static final int LENGTH = 1;
}
为方便起见,您可以静态导入代码中的常量:
import static com.example.Constants.*;
public class Test {
public static void main(String[] args){
System.out.println(DELIMITER); // prints "-"
}
}
答案 3 :(得分:0)
只有1值的枚举可能没有多大意义,尽管如果计划扩展它可能包含的任何值,它可能会有用。
您所说的替代方法如下:
有一个暴露项目范围常量的公共类。当您的应用程序启动时,您可以使此类从某个配置文件中加载它的值,以便您可以控制这些常量的值。
为您的阅读和写作方法设置一组单独的方法,后缀为WithDefaultValues
。反过来,这些方法将调用您的其他方法并传入默认参数。
作为旁注,简单地重载您已经拥有的方法可能是有意义的,因此您有一个默认为这些常量的实现。如果是这种情况,请务必在方法签名中记录。
答案 4 :(得分:0)
IMO,Enum在这种情况下是矫枉过正的。 Enums用于枚举。
对于全局常量,您可以在java类或java接口中创建公共静态final类属性,尽管最新的不是常用方法(请参阅Interfaces with static fields in java for sharing 'constants')
答案 5 :(得分:0)
我建议另一个不使用WriteMyData
和ReadMyData
中任何常量的解决方案。
将分隔符和长度作为构造函数参数传递。这样,您就可以使用可能使测试更容易的参数对这些类进行单元测试。
当每个实例对分隔符和长度使用相同的值很重要时,两者都应在同一位置实例化并供客户端使用。创建实例的位置是使分隔符和长度值具有常量的适当位置。
答案 6 :(得分:0)
您可以创建一个界面 默认情况下,界面中的常量是静态的和最终的 您可以通过引用接口来使用这些变量。
public interface AnyNameInterface {
String AnyVar ="DEMO";
Double AnyVar_2 = 123.00;
}
用作:
AnyNameInterface.AnyVar
AnyNameInterface.AnyVar_2
答案 7 :(得分:0)
我想补充一点,即使有枚举的东西,枚举也不能总是被用作常量的容器,即使它们很好。
例如, javax.ws.rs.Path 定义String类型的单个注释类型元素。但是,这不会编译:
@Path(MyEnum.BASE_PATH)
也不会
@Path(MyEnum.BASE_PATH.name())
此外,在 可能无法定义类本身或某些常见超类的常量的情况下,讨论通常似乎是在定义类中的常量与一个界面。第三种选择可以是在注释中定义它们。
public @interface MyAnnotation {
String QUESTIONS = "/questions";
String ANSWERS = "/answers"; }
注释方法避开"常量界面"陷阱。在我的理解中,这个缺陷并不是说接口作为一个常量容器本身就是一个坏主意,问题是当调用者决定实现接口时,而不是通过例如访问常量。静态导入。