Подтвердить что ты не робот

Незаконные ссылки и переходы вперед

Я программирую игру в 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;
   }
}

Есть ли способ обойти эту проблему, используя перечисления, которые так же просты?

4b9b3361

Ответ 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();
  }
}