私は何度もこの問題に直面したようで、間違ったツリーを吠えているだけなのかコミュニティに尋ねたかった. 基本的に、私の質問は次のように要約できます。値が重要な列挙型 (Java の場合) がある場合、列挙型を使用する必要がありますか、それともより良い方法がありますか?列挙型を使用する場合はどうすればよいですか?ルックアップを逆にする最良の方法は何ですか?
これが例です。特定の月と年を表す Bean を作成したいとします。次のようなものを作成する場合があります。
public interface MonthAndYear {
Month getMonth();
void setMonth(Month month);
int getYear();
void setYear(int year);
}
ここでは、月を Month という別のクラスとして保存しているため、タイプ セーフになっています。int だけを入力すると、誰でも 13、5,643、または -100 を数値として渡すことができ、コンパイル時にそれをチェックする方法がなくなります。列挙型として実装する月を入れるように制限しています。
public enum Month {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER;
}
ここで、書き込みたいバックエンド データベースがあり、整数形式のみを受け入れるとします。これを行う標準的な方法は次のようです。
public enum Month {
JANUARY(1),
FEBRUARY(2),
MARCH(3),
APRIL(4),
MAY(5),
JUNE(6),
JULY(7),
AUGUST(8),
SEPTEMBER(9),
OCTOBER(10),
NOVEMBER(11),
DECEMBER(12);
private int monthNum;
public Month(int monthNum) {
this.monthNum = monthNum;
}
public getMonthNum() {
return monthNum;
}
}
かなり簡単ですが、これらの値をデータベースから読み取るだけでなく、書き込む場合はどうなりますか? int を取り、それぞれの Month オブジェクトを返す enum 内の case ステートメントを使用して、静的関数を実装できます。しかし、これは、何かを変更した場合、この関数とコンストラクターの引数を変更する必要があることを意味します - 2 つの場所で変更します。これが私がやってきたことです。まず、リバーシブル マップ クラスを次のように作成しました。
public class ReversibleHashMap<K,V> extends java.util.HashMap<K,V> {
private java.util.HashMap<V,K> reverseMap;
public ReversibleHashMap() {
super();
reverseMap = new java.util.HashMap<V,K>();
}
@Override
public V put(K k, V v) {
reverseMap.put(v, k);
return super.put(k,v);
}
public K reverseGet(V v) {
return reverseMap.get(v);
}
}
次に、コンストラクターメソッドの代わりに列挙型内にこれを実装しました。
public enum Month {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER;
private static ReversibleHashMap<java.lang.Integer,Month> monthNumMap;
static {
monthNumMap = new ReversibleHashMap<java.lang.Integer,Month>();
monthNumMap.put(new java.lang.Integer(1),JANUARY);
monthNumMap.put(new java.lang.Integer(2),FEBRUARY);
monthNumMap.put(new java.lang.Integer(3),MARCH);
monthNumMap.put(new java.lang.Integer(4),APRIL);
monthNumMap.put(new java.lang.Integer(5),MAY);
monthNumMap.put(new java.lang.Integer(6),JUNE);
monthNumMap.put(new java.lang.Integer(7),JULY);
monthNumMap.put(new java.lang.Integer(8),AUGUST);
monthNumMap.put(new java.lang.Integer(9),SEPTEMBER);
monthNumMap.put(new java.lang.Integer(10),OCTOBER);
monthNumMap.put(new java.lang.Integer(11),NOVEMBER);
monthNumMap.put(new java.lang.Integer(12),DECEMBER);
}
public int getMonthNum() {
return monthNumMap.reverseGet(this);
}
public static Month fromInt(int monthNum) {
return monthNumMap.get(new java.lang.Integer(monthNum));
}
}
これで、私が望むすべてのことができますが、それでも間違っているように見えます。「列挙に意味のある内部値がある場合は、代わりに定数を使用する必要があります」と人々は私に提案しました。ただし、そのアプローチが私が探しているタイプセーフをどのように提供するかはわかりません。しかし、私が開発した方法は非常に複雑に思えます。この種のことを行う標準的な方法はありますか?
PS: 政府が新しい月を追加する可能性はかなり低いことはわかっていますが、全体像を考えてみてください。enum には多くの用途があります。