Devo estar tentando criar um enum reversível em Java ou há uma maneira melhor?
Eu pareço ter enfrentado esse problema muitas vezes e queria perguntar à comunidade se estou apenas latindo na árvore errada. Basicamente, minha pergunta pode ser resumida a isto: se eu tenho um enum (em Java) para o qual os valores são importantes, devo estar usando um enum ou existe uma maneira melhor, e se eu usar um enum, então o que é a melhor maneira de reverter a pesquisa?
Aqui está um exemplo. Suponha que eu queira criar um bean representando um mês e ano específicos. Eu poderia criar algo como o seguinte:
public interface MonthAndYear {
Month getMonth();
void setMonth(Month month);
int getYear();
void setYear(int year);
}
Aqui estou armazenando meu mês como uma classe separada chamada Mês, para que seja seguro para o tipo. Se eu apenas colocar int, então qualquer um poderia passar em 13 ou 5.643 ou -100 como um número, e não haveria maneira de verificar isso em tempo de compilação. Estou restringindo-os a colocar um mês que eu implementarei como um enum:
public enum Month {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER;
}
Agora suponha que eu tenha algum banco de dados de backend para o qual eu queira escrever, que aceita apenas o formato inteiro. Bem, a maneira padrão de fazer isso parece ser:
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;
}
}
Bastante direto, mas o que acontece se eu quiser ler esses valores do banco de dados e também escrevê-los? Eu poderia apenas implementar uma função estática usando uma instrução case dentro do enum que pega um int e retorna o respectivo objeto Month. Mas isso significa que se eu mudei alguma coisa, então eu teria que mudar essa função, assim como os argumentos do construtor - mude em dois lugares. Então aqui está o que eu tenho feito. Primeiro, criei uma classe de mapa reversível da seguinte forma:
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);
}
}
Então eu implementei isso dentro do meu enum em vez do método construtor:
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));
}
}
Agora isso faz tudo o que eu quero, mas ainda parece errado. As pessoas sugeriram para mim "se a enumeração tiver um valor interno significativo, você deveria estar usando constantes". No entanto, não sei como essa abordagem me daria o tipo de segurança que estou procurando. O caminho que desenvolvi parece muito complicado. Existe alguma maneira padrão de fazer esse tipo de coisa?
PS: Eu sei que a probabilidade do governo adicionar um novo mês é ... bastante improvável, mas pense no quadro maior - há muitos usos para enums.