实现响应式定向枚举的最简单方法是什么?

The easiest way to achieve a responsive orientation enum? java

我将以"最清晰"的方式快速展示我想要实现的目标:

1
2
3
4
5
public enum Orientation {
    NORTH, WEST, SOUTH, EAST }

public enum Turn {
    LEFT, RIGHT }

因此,我希望这两个枚举可以安全有效地根据移动查找更改的方向:

1
2
3
4
Orientation orient = Orientation.NORTH;
// orient points to NORTH now
orient = orient.turn(Turn.LEFT);
// orient points to WEST now

我尝试实现这一目标的第一个方法是创建一个地图:

1
 EnumMap<Orientation, EnumMap<Turn, Orientation>>

静态地绘制所有方向图,但这是一大块地图。而且可能有点过量,尽管会产生这种预期效果:

1
2
directionMap.get(NORTH).get(LEFT)
// the value would then be WEST

下一步我要做的是通过一个指南针类把所有的方向连接成一个圆。就像一个LinkedCircuitList…<->North<->East<->South<->West<->North<->所以指南针可以有一个静态函数,调用链接列表中的任何成员,然后向左或向右移动,从而正确地改变方向。但代码并没有按我想要的方式运行。

所以我最后的问题是,有没有人对这种代码有经验,或者有一个想法,如何以一种良好的枚举方式来实现期望的结果?


我看不出地图解决方案有什么问题。如果你想要更贴心的东西:

1
2
3
4
5
6
7
8
9
public enum Orientation {
    NORTH, EAST, SOUTH, WEST;

    private static Orientation[] vals = values();

    Orientation turnTo(Turn t) {
        return vals[(4 + this.ordinal() + (t == Turn.RIGHT ? 1 : -1)) % 4];
    }
}

然而,这是不太干净和可维护的(如果有人更改枚举的顺序,它将被破坏)。

稍微干净一点(但考虑不多):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public enum Orientation {
    NORTH(0), EAST(1), SOUTH(2), WEST(3);

    private final int p;

    Orientation(int p) {
        this.p = p;
    }

    private static Orientation[] vals = new Orientation[4];
    static {
        for( Orientation o : Orientation.values() )
            vals[o.p] = o;
    }

    Orientation turnTo(Turn t) {
        return vals[(4 + this.p + (t == Turn.RIGHT ? 1 : -1)) % 4];
    }
}


另一种让Java接受这一点的方法是使用方法而不是字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
enum Orientation {

    NORTH {
        Orientation left(){return WEST;}
        Orientation right(){return EAST;}
    },
    EAST {
        Orientation left(){return NORTH;}
        Orientation right(){return SOUTH;}
    },
    SOUTH {
        Orientation left(){return EAST;}
        Orientation right(){return WEST;}
    },
    WEST {
        Orientation left(){return SOUTH;}
        Orientation right(){return NORTH;}
    };

    abstract Orientation left();
    abstract Orientation right();

    public Orientation turn(Turn where){
        return where == Turn.LEFT ? this.left() : this.right();
    }
}

如果你愿意的话,你可以自己保存turn(),然后写类似Orientation.North.left()的东西。提供非常简洁的语法。


不使用序数,且易于理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public enum Orientation { NORTH, WEST, EAST, SOUTH;

    static {
        NORTH.left = WEST;
        NORTH.right = EAST;
        WEST.left = SOUTH;
        WEST.right = NORTH;
        EAST.left = NORTH;
        EAST.right = SOUTH;
        SOUTH.left = EAST;
        SOUTH.right = WEST;
    }

    private Orientation left;
    private Orientation right;

    public Orientation turnTo(Turn t) { return t == Turn.LEFT ? left : right; }
}

我认为你对循环列表的想法非常好:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public enum Turn {
    LEFT(-1), RIGHT(1);

    private final int offset;

    private Turn(int offset) {
        this.offset = offset;
    }

    public int offset() {
        return this.offset;
    }
}

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

    private static final List<Orientation> orientations =
        Arrays.asList(NORTH, EAST, SOUTH, WEST); // to not depend on ordinal

    public Orientation turn(Turn to) {
        int size = orientations.size();
        int myIndex = orientations.indexOf(this);
        int remainder = (myIndex + to.offset()) % size;
        int index = remainder < 0 ? size + remainder : remainder;
        return orientations.get(index);
    }
}

这似乎是可扩展的,即,硬向左将有一个-2偏移,并且方向的圆形列表应从左到右排列。