【发布时间】:2020-08-02 01:21:27
【问题描述】:
我有一个枚举,每个元素都有一个相反的元素。我想要一种优雅的方式将它封装在枚举的每个元素中。我的首选选项不合法,因为它使用前向引用。
enum Direction {
NORTH(SOUTH), SOUTH(NORTH), EAST(WEST), WEST(EAST);
private final Direction opposite;
Direction(Direction opposite) {
this.opposite = opposite;
}
public Direction getOpposite() {
return opposite;
}
}
使用供应商也是违法的。
enum Direction {
NORTH(() -> SOUTH), SOUTH(() -> NORTH), EAST(() -> WEST), WEST(() -> EAST);
private final Supplier<Direction> opposite;
Direction(Supplier<Direction> opposite) {
this.opposite = opposite;
}
public Direction getOpposite() {
return opposite.get();
}
}
这让我不得不重写该方法:
enum Direction {
NORTH{
public Direction getOpposite() {
return SOUTH;
}
},
SOUTH{
public Direction getOpposite() {
return NORTH;
}
},
EAST{
public Direction getOpposite() {
return WEST;
}
},
WEST{
public Direction getOpposite() {
return EAST;
}
};
public abstract Direction getOpposite();
}
使用开关:
enum Direction {
NORTH, SOUTH, EAST, WEST;
public Direction getOpposite() {
return switch(this) {
case NORTH -> SOUTH;
case SOUTH -> NORTH;
case EAST -> WEST;
case WEST -> EAST;
}
}
}
或者地图:
enum Direction {
NORTH, SOUTH, EAST, WEST;
private static final Map<Direction,Direction> OPPOSITES =
Map.of(NORTH, SOUTH, SOUTH, NORTH, EAST, WEST, WEST, EAST);
public Direction getOpposite() {
OPPOSITES.get(this);
}
}
没有任何一种选择比仅仅将相反的情况作为一个论点列出来那么简单或易读。
有没有避免前向引用问题的优雅方法?
【问题讨论】:
-
为什么不在
if..else中使用multiole或语句?? -
另一种选择是使用
static{..}初始化块在枚举值已经存在之后设置它们,就像在stackoverflow.com/a/18883717中一样 -
地图选项还不错。查找时间也很棒。这个问题有点武断和主观,因为标准是
elegant,不管这意味着什么。 -
我个人会使用 Map 并提供类似 public static Direction#inverse(Direction) 的函数,并使用私有静态最终 Map 并使用
guavaImmutableMap 作为 Map 实现。 -
switch语句相对于映射的优势在于,如果您稍后添加另一个枚举值,编译器会告诉您是否忘记更新案例。地图不会发生这种情况。