Java 相反方向的枚举

Java 相反方向的枚举,java,enums,Java,Enums,我目前正在进行一个地下城游戏项目,该项目由多个相互连接的房间组成 根据您所在的房间,您可以通过选择方向(北、南、东、西)进入您隔壁的房间 我已经用枚举类表示了方向,我正在寻找一种方法来实现北与南相反,东代表西(等等),以便在游戏的最终形式中创建所有房间的布局 这是我的Enum课程: public enum Direction { NORTH, EAST, SOUTH, WEST; public Direction getOppositeDirection

我目前正在进行一个地下城游戏项目,该项目由多个相互连接的房间组成

根据您所在的房间,您可以通过选择方向(北、南、东、西)进入您隔壁的房间

我已经用
枚举
类表示了方向,我正在寻找一种方法来实现
相反,
代表
西
(等等),以便在游戏的最终形式中创建所有房间的布局

这是我的
Enum
课程:

public enum Direction {
    NORTH,
    EAST,
    SOUTH,
    WEST;

    public Direction getOppositeDirection() {
        return Direction.values()[(this.ordinal()+2)%4];
    }

}

问题是,目前该方法不是很安全,在该方向上声明顺序的任何更改都会破坏该方法,关于如何更好地实现该方法的任何建议?

您可以将该方法抽象化,并为每个常量实现它

enum Direction {
    NORTH() {
        public Direction getOppositeDirection() {
            return SOUTH;
        }
    },
    EAST() {
        public Direction getOppositeDirection() {
            return WEST;
        }
    },
    SOUTH() {
        public Direction getOppositeDirection() {
            return NORTH;
        }
    },
    WEST() {
        public Direction getOppositeDirection() {
            return EAST;
        }
    };

    public abstract Direction getOppositeDirection();
}
不过有点罗嗦

下一种方法较短,但更难阅读

enum Direction {
    NORTH, EAST, SOUTH, WEST;

    static {
        (SOUTH.oppositeDirection = NORTH).oppositeDirection = SOUTH;
        (WEST.oppositeDirection = EAST).oppositeDirection = WEST;
    }

    private Direction oppositeDirection;

    public Direction getOppositeDirection() {
        return oppositeDirection;
    }
}

您可能还想在lambda中查找其他情况,但您需要使用一些作弊代码,因为在定义常量/字段之前,NORTH和EAST无法引用它们:

import java.util.function.Supplier;

public enum Direction {
  NORTH,
  EAST,
  SOUTH,
  WEST;

  private Supplier<Direction> opposite;

  private Direction() {
  }

  static { // initialize opposite field
    for (final Direction direction : Direction.values()) {
      direction.opposite = oppositeOf(direction);
    }
  }

  private static Supplier<Direction> oppositeOf(final Direction self) {
    switch (self) {
      case NORTH: return () -> SOUTH;
      case WEST:  return () -> EAST;
      case EAST:  return () -> WEST;
      case SOUTH: return () -> NORTH;
      default:    throw new IllegalStateException("Invalid opposite: " + self);
    }
  }

  public final Direction getOppositeDirection() {
    return opposite.get();
  }

  public static void main(final String[] args) {
    for (final Direction dir : Direction.values()) {
      System.out.println(dir + " is opposite of " + dir.getOppositeDirection());
    }
  }
}
导入java.util.function.Supplier;
公共枚举方向{
北,
东方,,
南方
西方;
相对的私人供应商;
私人指导(){
}
静态{//初始化相反字段
对于(最终方向:Direction.values()){
direction.contract=相反的(方向);
}
}
私人静态供应商反对(最终方向自我){
开关(自){
案例北:返回()->南;
案例西部:返回()->东部;
案例东:返回()->西;
案例南部:返回()->北部;
默认值:抛出新的IllegalStateException(“无效对立面:+self”);
}
}
公共最终方向getOppositeDirection(){
返回相反的get();
}
公共静态void main(最终字符串[]args){
对于(最终方向dir:Direction.values()){
System.out.println(dir+”与“+dir.getOppositeDirection()相反);
}
}
}
这与使用抽象方法相同,但更简洁(这里除外,因为您需要向代码中添加更多内容):直接读取相反方向的内容,而不是使用冗长的方法声明(如果您还需要添加其他方法,这是另一回事)

此外,它不会为每个枚举常量(例如:
方向$1
方向$2
,…)创建伪类,因为不需要这样做。

简明的答案是:

public Direction getOppositeDirection() {
    return
        this==NORTH ? SOUTH :
        this==EAST  ? WEST :
        this==SOUTH ? NORTH :
                      EAST;
}
你可能更喜欢案例陈述

public Direction getOppositeDirection() {
    switch (this) {
        case NORTH: return SOUTH;
        case EAST:  return WEST;
        case SOUTH: return NORTH;
        case WEST:  return EAST;
        default: throw new Error();
    }
}

我觉得最简单的方法是按照您最初建议的方式进行,但在构造函数中接受一个参数:

public static enum Direction {
  NORTH(0),
  WEST(1),
  SOUTH(2),
  EAST(3);

  private int dir;

  private Direction(int dir) {
    this.dir = dir;
  }

  public static Direction getNewDirection(int dir) {
    // ensure direction is in [0, 4)
    dir %= 4;
    if (dir < 0) dir += 4;
    for (Direction d : Direction.values()) {
      if (d.dir == dir) return d;
    }
    throw new Error();
  }

  public Direction getOppositeDirection() {
    return getNewDirection(dir + 2);
  }
}
公共静态枚举方向{
北(0),,
西(1),
南部(2),
东(3);
私人内部目录;
私人方向(内部方向){
this.dir=dir;
}
公共静态方向getNewDirection(int dir){
//确保方向为[0,4]
dir%=4;
如果(dir<0)dir+=4;
对于(方向d:Direction.values()){
如果(d.dir==dir)返回d;
}
抛出新错误();
}
公共方向getOppositeDirection(){
返回getNewDirection(dir+2);
}
}

这样做的好处很多:方向基本上形成了一组旋转,对应于模4的整数。它们自然地表示为模4的整数。现在,如果我们想得到顺时针方向,我们可以很容易地(
getNewDirection(dir+1)
)或逆时针方向(
getNewDirection(dir-1)
)。如果角色面向方向
d1
,我们想知道转向新方向的方式
d2
,这对应于减法等。您可能希望执行的所有操作都有一种自然的方式,可以使用整数模4执行。

另一个选项可以是使用
映射(甚至可能是
EnumMap
),例如:

公共枚举方向{
北,
东方,,
南方
西方;
私有静态最终映射对立面=ImmutableMap.of(
北,南,,
东,西,,
南,北,,
西,东
);
公共方向相反方向{
返回对立面。得到(这个);
}
}

我考虑过,但它不应该编译,因为这里有两个非法的正向引用。没有正向引用:如果我直接在构造函数中传递字段,它会出错,但这里不是这种情况。在调用getOppositeDirection之前不会计算lambda。它不会为我编译。如果你是我的话ght.NORTH/EAST出现错误。在回答中修复了该错误。
供应商
s在使用静态初始化块时是多余的,甚至是
NORTH()
?它是一个方法吗?一个字段?
NORTH
方向
的一个恒定实例;为了成为一个有效的实例,它应该为所有抽象方法提供一个实现declared@DavidStockinger
NORTH(){…}
是确定要调用和提供/重写方法的构造函数的方法。这里,它是默认构造函数。如果我们有一个
方向(String s)
构造函数,我们可以使用
NORTH(“String”){…}
@AndrewTobilko这也增加了额外的好处,如果你想增加额外的方向,比如
东南部
-它不会编译而不提供相反的方向。我不理解否决票-这是我在阅读问题时想到的第一件事,1+还有这个:)但您应该使用EnumMap而不是Guava提供解决方案。
public enum Direction {

    NORTH,
    EAST,
    SOUTH,
    WEST;

    private static final Map<Direction, Direction> OPPOSITES = ImmutableMap.of(
        NORTH, SOUTH,
        EAST,  WEST,
        SOUTH, NORTH,
        WEST,  EAST
    );

    public Direction oppositeDirection() {
        return OPPOSITES.get(this);
    }
}