0

我目前正在编写解决旅行商问题的遗传算法。我在多个地方使用了一些“常量”。但是,这些值需要预先计算,因此,我无法将它们存储到私有静态最终变量中。因此,我决定使用枚举。

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;
    }
}

我的问题是,你认为这是一个好方法吗?我不确定这是否会降低使用枚举的每个类的凝聚力。提前致谢。

4

2 回答 2

1

这对我来说似乎是一个不好的方法。枚举就像类,因此为这些计算创建一个专用类没有太大区别。那么实际上为什么不只使用这两个字段而不是 Enum 创建典型的类,以将它们的实例保留为private static final字段呢?

于 2021-11-08T22:36:09.267 回答
0

正如所评论的,改变值的常数不是常数。

虽然您当然可以在枚举中存储变化的状态,但您应该问问自己这样做是否是个好主意。在我看来,一般不会。枚举对象通常用作常量,因此命名约定全部大写。

Map

您可以通过使用Map. 映射会将每个枚举对象与自定义类型的对象配对,以包含您不断变化的状态。

EnumMap

该类EnumMap是一个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+ 中,如果您愿意enumrecord可以在本地定义两者。

当然,这里显示的代码不是线程安全的;谨防。

于 2021-11-08T23:52:55.453 回答