使用常量相关的方法
常量相关的方法允许我们为每个enum实例提供方法的不同实现,
这使得常量相关的方法似乎是实现多路分发的完美解决方案。
不过,通过这种方式,enum实例虽然可以具有不同的行为,
但他们任然不是类型,不能将其作为方法签名中的参数类型
来使用。最好的办法是将enum用在switch语句中
import static enumerated.Outcome.*;
public enum RoShamBo3 implements Competitor<RoShamBo3>{
PAPER{
public Outcome compete(RoShamBo3 it){
switch(it){
default: // To placate the compiler
case PAPER: return DRAW;
case SCISSORS: return LOSE;
case ROCK: return WIN;
}
}
},
SCISSORS{
public Outcome compete(RoShamBo3 it){
switch(it){
default:
case PAPER: return WIN;
case SCISSORS: return DRAW;
case ROCK: return LOSE;
}
}
},
ROCK{
public Outcome compete(RoShamBo3 it){
switch(it){
default:
case PAPER: return LOSE;
case SCISSORS: return WIN;
case ROCK: return DRAW;
}
}
};
public abstract Outcome compete(RoShamBo3 it);
public static void main(String[] args){
RoShamBo.play(RoShamBo3.class, 20);
}
}
虽然这种方式可以工作, 却不合理, 如果采用RoShamBo解决方案, 在添加一个新
的类型时, 只需更少的代码, 而且更直接。
public enum RoShamBo4 implements Competitor<RoShamBo4>{
ROCK{
public Outcome compete(RoShamBo4 opponent){
return compete(SCISSORS, opponent);
}
},
SCISSORS{
public Outcome compete(RoShamBo4 opponent){
return compete(PAPER, opponent);
}
},
PAPER{
public Outcome compete(RoShamBo4 opponent){
return compete(ROCK, opponent);
}
};
Outcome compete(RoShamBo4 loser, RoShamBo4 opponent){
return ((opponent == this) ? Outcome.DRAW
: ((opponent == loser) ? Outcome.WIN
: Outcome.LOSE));
}
public static void main(String[] args) {
RoShamBo.play(RoShamBo4.class, 20);
}
}
2个参数的compete()方法执行第二个分发,该方法执行一系列的比较,
行为类似switch语句。 这个版本的程序简单,却比较难理解。
对于一个大型系统,难以理解的代码将导致系统不够健壮。
使用EnumMap分发
import static enumerated.Outcome.*;
public enum RoShamBo5 implements Competitor<RoShamBo5>{
PAPER, SCISSORS, ROCK;
static EnumMap<RoShamBo5, EnumMap<RoShamBo5, Outcome>>
table = new EnumMap<RoShamBo5, EnumMap<RoShamBo5, Outcome>>(RoShamBo5.class);
static{
for(RoShamBo5 it : RoShamBo5.values())
table.put(it,
new EnumMap<RoShamBo5, Outcome>(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);
}
public Outcome compete(RoShamBo5 it) {
return table.get(this).get(it);
}
public static void main(String[] args) {
RoShamBo.play(RoShamBo5.class, 20);
}
}
使用二维数组
还可以进一步简化实现两路分发的解决方案, 每个enum实例都有一个固定的值(基于声明的次序),
并且可以通过ordinal()方法取得该值。因此我们可以使用二维数组,将竞争者映射到
竞争的结果。 这种方式能够获得最简洁,最直接的解决方案
public enum RoShamBo6 implements Competitor<RoShamBo6>{
PAPER, SCISSORS, ROCK;
private static Outcome[][] tables = {
{DRAW, LOSE, WIIN}, //PAPER
{LOSE, WIN, DRAW}, //ROCK
{WIN, DRAW, LOSE}, //SCISSOR
};
public Outcome compete(RoShamBo6 other){
return table[this.ordinal()][other.ordinal()];
}
public static void main(String[] args){
RoShamBo.play(RoShamBo6.class, 20);
}
}