使用 EnumMap 可以实现“真正的”双路分发,它是专门为 enum 设计的高效 Map。我们的目标是在两个未知类型中切换,因此由 EnumMap 组成的 EnumMap (嵌套 EnumMap )可以实现双路分发。
RoShamBo5.java
import java.util.EnumMap;
import static enums.TEST0006.Outcome.*;
enum RoShamBo5 implements Competitor<RoShamBo5> {
PAPER, SCISSORS, ROCK;
static EnumMap<RoShamBo5, EnumMap<RoShamBo5, Outcome>> table = new EnumMap<>(RoShamBo5.class);
static {
for (RoShamBo5 it : RoShamBo5.values()) {
table.put(it, new EnumMap<>(RoShamBo5.class));
}
initRow(PAPER, DRAW, LOSE, WIN);
initRow(SCISSORS, WIN, DRAW, LOSE);
initRow(ROCK, LOSE, WIN, DRAW);
}
static void initRow(RoShamBo5 it,Outcome vPAPER, Outcome vSCISSORS, Outcome vROCK) {
EnumMap<RoShamBo5, Outcome> row =RoShamBo5.table.get(it);
row.put(RoShamBo5.PAPER, vPAPER);
row.put(RoShamBo5.SCISSORS, vSCISSORS);
row.put(RoShamBo5.ROCK, vROCK);
}
@Override
public Outcome compete(RoShamBo5 it) {
return table.get(this).get(it);
}
public static void main(String[] args) {
RoShamBo.play(RoShamBo5.class, 20);
}
}
Competitor.java
public interface Competitor<T extends Competitor<T>> {
Outcome compete(T competitor);
}
Outcome.java
public enum Outcome {WIN, LOSE, DRAW}
Enums.java
import java.util.Random;
public class Enums {
private static Random rand = new Random(47);
public static <T extends Enum<T>> T random(Class<T> ec) {
return random(ec.getEnumConstants());
}
public static <T> T random(T[] values) {
return values[rand.nextInt(values.length)];
}
}
RoShamBo.java
public class RoShamBo {
public static <T extends Competitor<T>>
void match(T a, T b) {
System.out.println(a + " vs. " + b + ": " + a.compete(b));
}
public static <T extends Enum<T> & Competitor<T>>
void play(Class<T> rsbClass, int size) {
for (int i = 0; i < size; i++) {
match(Enums.random(rsbClass), Enums.random(rsbClass));
}
}
}
运行结果如下:
EnumMap 是用一个 static() 子句进行初始化的,可以看到对 initRow() 的调用是类似表格的结构。注意 compete() 方法,其在内部的一条语句内发生了两次分发。