使用 Enum 存储常量并在多个 类 中使用这些常量
Using Enum to store constants and use those constants in multiple classes
我目前正在编写解决旅行商问题的遗传算法。我在多个地方使用了一些“常量”。但是,这些值需要预先计算,因此,我无法将它们存储到私有静态最终变量中。
因此,我决定使用枚举。
public enum Constants {
NODE_COUNT(0),
SEQUENCE_LENGTH(0),
POPULATION_SIZE(0),
MAX_EDGE_WEIGHT(0),
MUTATION_RATE(0);
private int value;
private boolean alreadySet = false;
Constants(int value) {
this.value = value;
}
public void setValue(int value) {
if (!alreadySet) {
this.value = value;
this.alreadySet = true;
} else {
throw new AssertionError("Value is already set.");
}
}
public int get() {
return value;
}
}
我的问题是,您认为这是一个好方法吗?我不确定这是否会降低每个 class 使用枚举的凝聚力。
提前致谢。
这对我来说似乎是一个糟糕的方法。枚举类似于 classes,因此为这些计算制作专用的 class 并没有太大区别。那么实际上为什么不只用这两个字段而不是枚举来创建典型的 class,以将它们的实例保持为 private static final
字段?
如,改变值的常量不是常量。
虽然您当然可以在枚举上存储不断变化的状态,但您应该问问自己这样做是否是个好主意。在我看来,一般不会。枚举对象通常用作常量,因此命名约定全部大写。
Map
您可以通过使用 Map
来实现拥有类型安全的有限对象集(枚举)以及更明显地改变状态的目标。映射会将每个枚举对象与自定义类型的对象配对以包含您不断变化的状态。
EnumMap
EnumMap
class 是 Map
的一个实现,效率高,占用内存少,CPU。
这里有一些未经测试的代码作为例子。
enum TravSalesAspect NODE_COUNT, SEQUENCE_LENGTH, POPULATION_SIZE, MAX_EDGE_WEIGHT, MUTATION_RATE ;
record AlgorithmState ( int val , boolean alreadySet ) {}
final Map< TravSalesAspect , AlgorithmState > map = new EnumMap<>() ;
我们的地图是空的。所以我们想用一些默认值进行初始化。
我们访问所有枚举对象的数组。从那个数组中,我们创建了一个流。对于流中的每个元素,我们将一个键值条目放入映射中。
Arrays.stream( TravSalesAspect.values() ).forEach( aspect -> map.put( aspect , new AlgorithmState( 0 , false ) ) ) ; // Initializing the map.
当你想稍后设置状态时:
if( ! map.get( someAspect ).alreadySet() )
{
map.put( someAspect , new AlgorithmState( 42 , true ) ) ;
}
顺便说一下,请注意,在 Java 16+ 中,如果您愿意,enum
和 record
都可以是 defined locally。
当然这里显示的代码不是线程安全的;当心。
我目前正在编写解决旅行商问题的遗传算法。我在多个地方使用了一些“常量”。但是,这些值需要预先计算,因此,我无法将它们存储到私有静态最终变量中。 因此,我决定使用枚举。
public enum Constants {
NODE_COUNT(0),
SEQUENCE_LENGTH(0),
POPULATION_SIZE(0),
MAX_EDGE_WEIGHT(0),
MUTATION_RATE(0);
private int value;
private boolean alreadySet = false;
Constants(int value) {
this.value = value;
}
public void setValue(int value) {
if (!alreadySet) {
this.value = value;
this.alreadySet = true;
} else {
throw new AssertionError("Value is already set.");
}
}
public int get() {
return value;
}
}
我的问题是,您认为这是一个好方法吗?我不确定这是否会降低每个 class 使用枚举的凝聚力。 提前致谢。
这对我来说似乎是一个糟糕的方法。枚举类似于 classes,因此为这些计算制作专用的 class 并没有太大区别。那么实际上为什么不只用这两个字段而不是枚举来创建典型的 class,以将它们的实例保持为 private static final
字段?
如
虽然您当然可以在枚举上存储不断变化的状态,但您应该问问自己这样做是否是个好主意。在我看来,一般不会。枚举对象通常用作常量,因此命名约定全部大写。
Map
您可以通过使用 Map
来实现拥有类型安全的有限对象集(枚举)以及更明显地改变状态的目标。映射会将每个枚举对象与自定义类型的对象配对以包含您不断变化的状态。
EnumMap
EnumMap
class 是 Map
的一个实现,效率高,占用内存少,CPU。
这里有一些未经测试的代码作为例子。
enum TravSalesAspect NODE_COUNT, SEQUENCE_LENGTH, POPULATION_SIZE, MAX_EDGE_WEIGHT, MUTATION_RATE ;
record AlgorithmState ( int val , boolean alreadySet ) {}
final Map< TravSalesAspect , AlgorithmState > map = new EnumMap<>() ;
我们的地图是空的。所以我们想用一些默认值进行初始化。
我们访问所有枚举对象的数组。从那个数组中,我们创建了一个流。对于流中的每个元素,我们将一个键值条目放入映射中。
Arrays.stream( TravSalesAspect.values() ).forEach( aspect -> map.put( aspect , new AlgorithmState( 0 , false ) ) ) ; // Initializing the map.
当你想稍后设置状态时:
if( ! map.get( someAspect ).alreadySet() )
{
map.put( someAspect , new AlgorithmState( 42 , true ) ) ;
}
顺便说一下,请注意,在 Java 16+ 中,如果您愿意,enum
和 record
都可以是 defined locally。
当然这里显示的代码不是线程安全的;当心。