Posted at

Javaで相関関係がある列挙型を定義する

More than 5 years have passed since last update.

この記事はTumblrでも公開しています


はじめに

Javaの列挙型はメソッドを持つことはできますが、メソッド中で識別子による条件分岐処理を入れることは、列挙型の特徴を捉えておらず、また可読性の面であまりいい設計ではありません。

その問題を解消するための方法を忘備録としてメモします。


方法

例として、Colorという列挙型を考えます。Colorは、WHITE識別子の裏はBLACK、またBLACK識別子の裏はWHITEという相関関係を持ちます。

まず一番シンプルな列挙型は以下のようになります。

enum Color {

WHITE, BLACK;
}

これに、WHITEの裏はBLACK、またBLACKの裏はWHITEという相関関係を定義するために以下のようにinverseメソッドを定義します。

enum Color {

WHITE, BLACK;

public Color inverse() {
if (this == WHITE) {
return BLACK;
} else {
return WHITE;
}
}
}

この書き方でも期待した動作はしますが、例えばコンストラクタを持たせた場合、列挙型Colorの性質を表す部分が分離して可読性が下がります。

そこでインスタンス変数とコンストラクタを用いて、以下のように設定しようとしました。

enum Color {

WHITE(BLACK), BLACK(WHITE);

public final Color inverse;
Color(Color inverse) {
this.inverse = inverse;
}
}

しかし、これはコンパイルするとエラーがでます。

$ javac Color.java

Color.java:2: エラー: 前方参照が不正です
WHITE(BLACK), BLACK(WHITE);
^
エラー1個

WHITEのコンストラクタが呼ばれた時に、まだ宣言されていないBLACKを参照していることが原因です。

これを解決するために、Color列挙型に抽象メソッドを宣言し、それぞれの識別子で独自関数としてオーバーライドしました。

enum Color {

WHITE{
@Override
public Color inverse() {
return BLACK;
}
},
BLACK{
@Override
public Color inverse() {
return WHITE;
}
};

abstract Color inverse();
}

これによって今後の拡張をする際にも列挙型の性質を一つの部位に書くことができます。


まとめ


  • コンストラクタで相関関係を定義すると、前方参照のエラーが起きる。

  • 相関関係を定義するときには、抽象メソッドを識別仕事に独自関数としてオーバーライドして実現する。