1

I'm currently writing a genetic algorithm solving the traveling salesman problem. There are some "constants" I use at multiple places. Those values, however, need to be precalculated, thus, I can't store them into a private static final variable. Hence, I decided to use an Enum.

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

My question is, do you consider this a good approach? I'm not sure whether this lowers the cohesion of each class using the enum. Thanks in advance.

2 Answers2

1

This seems to be a bad approach to me. Enums are like classes, so there's no huge difference of making a dedicated class for those calculations. Then in fact why not creating typical class with those two fields only and instead of Enum, to keep their instances as private static final fields?

Andret2344
  • 653
  • 1
  • 12
  • 33
  • That is what I'm struggling with. For instance, NODE_COUNT: I use the graphStream library, so I can get node count of a graph by graph.getNodeCount(). (same for max edge weight). But I thought it might be better to precalculate those values (performance), as they never change. Using a private static final filed is not possible here. – John The Fisherman Nov 08 '21 at 23:22
0

As commented, a constant that changes value is not a constant.

While you certainly can store changing state on an enum, you should ask yourself if doing so is a good idea. Generally not, in my opinion. Enum objects are usually used as constants, hence the convention of naming in all uppercase.

Map

You can accomplish the goal of having type-safe limited set of objects (enums) along with more obviously changing state by using a Map. A map would pair each enum object with an object of a custom type to contain your changing state.

EnumMap

The EnumMap class is an implementation of Map that is highly efficient, taking little memory and little CPU.

Here is some untested code as an example.

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<>() ;

Our map is empty. So we want to initialize with some default values.

We access an array of all the enum objects. From that array, we make a stream. For each element in the stream, we put a key-value entry into the map.

Arrays.stream( TravSalesAspect.values() ).forEach( aspect -> map.put( aspect , new AlgorithmState( 0 , false ) ) ) ;  // Initializing the map.

When you want to later set the state:

if( ! map.get( someAspect ).alreadySet() ) 
{
    map.put( someAspect , new AlgorithmState( 42 , true ) ) ; 
}

By the way, note that in Java 16+ both enum and record can be defined locally if you so desire.

Of course the code shown here is not thread-safe; beware.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154