Незаконные ссылки и переходы вперед
Я программирую игру в java, которая состоит из сетки плиток. Я не смог бы интуитивно определить края плиток и как они связаны друг с другом, например. чтобы получить противоположный край плитки, я хочу иметь возможность просто набрать TOP.opposite()
. Однако при использовании перечислений для определения этих ребер мне приходится пересылать ссылку по крайней мере из двух из них в контрструкторе:
public enum Edge {
TOP(Edge.BOTTOM), //illegal forward reference
BOTTOM(Edge.TOP),
LEFT(Edge.RIGHT), //illegal forward reference
RIGHT(Edge.LEFT);
private Edge opposite;
private Edge(Edge opp){
this.opposite = opp;
}
public Edge opposite(){
return this.opposite;
}
}
Есть ли способ обойти эту проблему, используя перечисления, которые так же просты?
Ответы
Ответ 1
Вы можете сделать это, что не так интуитивно.
public enum Edge {
TOP, BOTTOM, LEFT, RIGHT;
private Edge opposite;
static {
TOP.opposite = BOTTOM;
BOTTOM.opposite = TOP;
LEFT.opposite = RIGHT;
RIGHT.opposite = LEFT;
}
public Edge opposite(){
return this.opposite;
}
}
Ответ 2
enum Edge {
TOP {
@Override
public Edge opposite() {
return BOTTOM;
}
},
BOTTOM {
@Override
public Edge opposite() {
return TOP;
}
},
LEFT {
@Override
public Edge opposite() {
return RIGHT;
}
},
RIGHT {
@Override
public Edge opposite() {
return LEFT;
}
};
public abstract Edge opposite();
}
Ответ 3
public enum Edge {
TOP,
BOTTOM(Edge.TOP),
LEFT,
RIGHT(Edge.LEFT);
private Edge opposite;
private Edge() {
}
private Edge(Edge opp) {
this.opposite = opp;
opp.opposite = this;
}
public Edge opposite() {
return this.opposite;
}
}
Ответ 4
Здесь другой путь
public enum Edge {
TOP("BOTTOM"),
BOTTOM("TOP"),
LEFT("RIGHT"),
RIGHT("LEFT");
private String opposite;
private Edge(String opposite){
this.opposite = opposite;
}
public Edge opposite(){
return valueOf(opposite);
}
}
Решение Питера Лоури, однако, более эффективно и безопасно.
Ответ 5
Вы также можете использовать статический внутренний класс внутри перечисления:
public enum EnumTest
{
NORTH( Orientation.VERTICAL ),
SOUTH( Orientation.VERTICAL ),
EAST( Orientation.HORIZONTAL ),
WEST( Orientation.HORIZONTAL );
private static class Orientation
{
private static final String VERTICAL = null;
private static final String HORIZONTAL = null;
}
}
Украден из здесь:)
Ответ 6
Вы можете создать статический Map
, где ключ является исходным перечислением, а значение - противоположным. Инициализируйте его в статическом блоке и верните отображение из метода opposite()
.
private static Map<Edge, Edge> oppostiteMapping;
static {
oppositeMapping = new EnumMap<Edge, Edge>();
oppositeMapping.put(TOP, BOTTOM);
...
}
public Edge opposite() {
return oppositeMapping.get(this);
}
EDIT:, как было предложено в комментарии, лучше использовать EnumMap, поэтому я обновил соответственно
Btw. этот подход обычно полезен, когда вы создаете что-то вроде статического метода fromString()
и т.д.
Ответ 7
Вы можете просто определить метод, аналогичный описанному ниже.
public enum Edge {
TOP,
BOTTOM,
LEFT,
RIGHT;
public Edge opposite() {
switch (this) {
case TOP:
return Edge.BOTTOM;
case BOTTOM:
return Edge.TOP;
case LEFT:
return RIGHT;
case RIGHT:
return LEFT;
default:
throw new RuntimeException("Oh dear");
}
}
}
Ответ 8
Вместо этого вы можете использовать внутреннюю карту, чтобы определить эти ассоциации. Это работает, если в момент инициализации Карты вы уже создали все значения перечисления:
public enum Edge {
TOP,
BOTTOM,
LEFT,
RIGHT;
private static final Map<Edge, Edge> opposites =
new EnumMap<Edge, Edge>(Edge.class);
static {
opposites.put(TOP, BOTTOM);
opposites.put(BOTTOM, TOP);
opposites.put(LEFT, RIGHT);
opposites.put(RIGHT, LEFT);
}
public Edge opposite(){
return opposites.get(this);
}
}
Ответ 9
Я предпочел это:
public enum Edge {
TOP,
BOTTOM,
LEFT,
RIGHT;
private Link link;
private Link getLink() {
if (link == null) {
link = Link.valueOf(name());
}
return link;
}
public Edge opposite() {
return getLink().opposite();
}
}
public enum Link {
TOP(Edge.BOTTOM),
BOTTOM(Edge.TOP),
LEFT(Edge.RIGHT),
RIGHT(Edge.LEFT);
private Edge opposite;
private Link(Edge opp) {
this.opposite = opp;
}
public Edge opposite() {
return this.opposite;
}
}
Ответ 10
С Java 8 lambdas:
public enum Edge {
TOP(() -> Edge.BOTTOM),
BOTTOM(() -> Edge.TOP),
LEFT(() -> Edge.RIGHT),
RIGHT(() -> Edge.LEFT);
private Supplier<Edge> opposite;
private Edge(Supplier<Edge> opposite) {
this.opposite = opposite;
}
public Edge opposite() {
return opposite.get();
}
}