Consider the following sscce
public enum Flippable
A (Z), B (Y), Y (B), Z (A);
private final Flippable opposite;
private Flippable(Flippable opposite) {
this.opposite = opposite;
}
public Flippable flip() {
return opposite;
}
}
This doesn't compile, because Z
and Y
haven't been declared to be allowed to be arguments of A
and B
's constructor.
Potential solution 1: Hardcoded Methods
public enum Flippable {
A {
public Flippable flip() { return Z; }
}, B {
public Flippable flip() { return Y; }
}, Y {
public Flippable flip() { return B; }
}, Z {
public Flippable flip() { return A; }
};
public abstract Flippable flip();
}
While functional, this seems stylistically quite gross. Though I can't put a finger on why this would be a real problem.
Potential solution 2: static loading
public enum Flippable {
A, B, Y, Z;
private Flippable opposite;
static {
for(Flippable f : Flippable.values()) {
switch(f) {
case A:
f.opposite = Z;
break;
case B:
f.opposite = Y;
break;
case Y:
f.opposite = B;
break;
case Z:
f.opposite = A;
break;
}
}
}
public Flippable flip() {
return opposite;
}
}
This is even more gross than the first solution, as the field is no longer final, and is vulnerable to reflection. Ultimately that is an obscure worry, but suggests a bad code smell.
Is there a way to do this that is essentially the same as the first example, but compiles properly?