2013-02-08 6 views
5

Iは気づくことJava Enum Documentation状態序方法:使用は、

この列挙定数の序数(初期定数の序数が割り当てられ、その列挙宣言、その位置を返しゼロ)。ほとんどのプログラマーはこのメソッドを使用しません。 EnumSetやEnumMapなどの洗練されたenumベースのデータ構造で使用するように設計されています。

は、私は配列のインデックスへordinalを使用しないようお勧めオンラインすべての例を理解する代わりにEnumMap。特にItem 33 of Effective Java 私の質問です:それは私のEnumの定義内で使用するのは大丈夫ですか?

public enum Direction { 
    NORTH(0, 1), NORTH_EAST(1, 1), EAST(1, 0), SOUTH_EAST(1, -1), 
    SOUTH(0, -1), SOUTH_WEST(-1, 1), WEST(-1, 0), NORTH_WEST(-1, 1); 

    private final int xOffset; 
    private final int yOffset; 

    private final static int DEGREES = 360; 

    private Direction(int xOffset, int yOffset) { 
    this.xOffset = xOffset; 
    this.yOffset = yOffset; 
    } 

    public Position move(Position position) { 
    return new Position(position.getX() + xOffset, position.getY() + yOffset); 
    } 

    public Direction rotate(int degrees) { 
    int length = Direction.values().length; 
    int index = (ordinal() + (degrees/(DEGREES/length))) % length; 
    return Direction.values()[index]; 
    } 
} 

あなたは私が序()を使用しています見ることができるように私ができるように、方向を循環(および次の関連する方向を返す): は、たとえば私のコードは次のとおりです。例えば。 NORTHから90度回転すると、EASTが返されます。

しかし、序数を使用するのは良い方法ではないことがわかっているので、コードサイズを小さくして可読性を維持しながら、これを行うより良い方法があるかどうかは疑問でした。

アドバイスをいただきありがとうございます。

答えて

4

私はこれが完全に受け入れられるordinalだと言います。実際、それは私の意見では、非常にきれいでシンプルです。

あなたenumコードでordinalを使用しないことについてのコメントは、ほとんどの時間は、あなたの代わりにenum自体またはEnumMapを使用することができますので、そうすることからあなたを思いとどまらせるだけです。

EffectiveJavaへの参照は、配列に対してオフセットとして使用する正しいintを選択するのが難しく、一般的に不要なので、これを行うことを警告しています。あなたのケースでは、a)あなたはそれを正しくやっているので、b)それはあなたが探している機能を達成するための最も簡単な方法ですので、適用されません。

+0

効果的なJavaを慎重に読んでいれば(項目31)、実際には、新しい要素を列挙型に追加することができないため、このようにordinalを使用することは勧められます。この場合も、WEST_FAR_AWAY(-10、0)要素によってコードが中断されます。だから、ジョシュア・ブロッホはこのコードを承認しないでしょう。これはすばやく汚れた解決策です。それはOK(作業中)ですが、最高です。 – lbalazscs

+0

@ibalazscs - この場合、新しい 'enum'を追加することは意味をなさないでしょう。あなたのWEST_FAR_AWAYは全く意味をなさないでしょう。 – OldCurmudgeon

+0

私はそれが理にかなっている多くのシナリオを考えることができます。例えば、移動メソッドはオフセットを使用し、異なるオフセットを持つ方向を使用して高速に動くものを実装することができます。または、何らかの理由でSOUTH_WESTを削除する必要があります。これは、この脆弱なコードを破ることにもなります。 – lbalazscs

1

Enum定義で使用するのは問題ありませんか?

大丈夫です。しかし、理由はよくあなたが提供されたリンクに記載されてそれを使用するとEnumMapのために行くことはない

このプログラム作品(それはそれで説明した例に言及していたとして引用は変更部分だ)とさえエレガント表示される場合があります外見は欺くことができます。コンパイラのように、序数と配列インデックスの間の関係を知る方法はありません。変更を加えてそれに応じて更新することを忘れると、実行時にプログラムが失敗します。

EnumMapは、あなたのデザインにあなたのデザインに含めると非常に効率的です。

+0

このデザインでEnumMapをどのように使うのか分かりませんが?これはMap (つまり次の方向)になりますか?この例では、実際のハーブのセットにタイプenumとストアタイプを使用するハーブがあります。私は現在の方向から45度(私の場合)の方位を見つけることに興味があります。私はあなたがEnumMapをどのように定義するのかとは考えていません。 –

+0

はい。それは似たような行為ではなく、私も統合するのが難しいと感じています。西のようなすべての度合いで方向を取得する必要があるので、180 *の回転後に東を与える必要があります。ここでは1..nマッピングのほうが似ています。したがって、現在のデザインは良好ですが、変更を導入する際には注意が必要です。複雑なトレースが不可能なバグにつながる可能性があります。 – mtk

2

WEST_FAR_AWAY(-10、0)のように、今後誰かが新しいメンバーを導入すると、コードが破損することがあります。アプリケーションの要件に応じて、これが「マイナーで許容可能な欠陥」か「メンテナンスの悪夢」かどうかを評価する必要があります。

+0

私はこれがマイナーフロアだと主張したいと思います。これは、enumが設計されたものではなく、私のコードによく書かれています。 –

+1

それでは、このようにしてください。私たちが実用的な方法でそれを見ると、クラス内で柔軟性のないものを実行することは、アプリケーションの残りの部分が「感染していない」限り、それほど悪くはありません。この場合、後で気を付け直す場合は、1つのメソッドを書き直すだけです。 – lbalazscs

+0

適切な単体テストを追加することで、メンテナンスの悪夢を防ぐことができます。また、 'ordinal()'の使用法を説明するコードコメントを追加すると、新しいenum値を追加するのが問題になります。 –