Intro
Muitas pessoas não utilizam os tipos enumerados em Java, seja por não conhecerem por estar começando a programar em Java ou, no caso dos experientes, serem relutantes a mudanças (enums foram introduzidos no Java 5).
O fato é que enums quebram um galhão e, diferente como alguns pensam, não são apenas constantes (como é no C# por exemplo), eles podem ter atributos e métodos.
Para entender a utilidade de enums vamos aplicá-los em dois estudos de caso:
1: Uma refatoração de "obsessão primitiva" (um mau cheiro)
2: Introdução do Design Pattern Strategy (Padrão de Projeto Estratégia)
Neste post vou abordar o uso de enums em refatorações e no próximo post abordo o segundo caso, ok?
Usando enums em refatorações
Imagine a seguinte implementação:
public class Usuario {
String nome;
String login;
String senha;
int perfil = 0;
}
Não fica claro o que perfil quer dizer, fica?
Então podemos adicionar um comentário! (a.k.a. desodorante!)
public class Usuario {
String nome;
String login;
String senha;
// perfil do usuário pode ser:
// 0:visitante,
// 1:usuário,
// 2:funcionário,
// 3:gerente,
// 4:administrador
int perfil = 0;
}
Há ainda os que colocam caracteres de destaque no comentário (péssimo amigo):
// --------------------------------------------------------- //
// perfil do usuário pode ser: //
// 0:visitante, //
// 1:usuário, //
// 2:funcionário, //
// 3:gerente, //
// 4:administrador //
// --------------------------------------------------------- //
int perfil = 0;
Steve McConnel, respeitado Engenheiro de Software diz:
Bom código é sua melhor documentação. Sempre que você estiver por adicionar um comentário, pergunte a si mesmo: 'Como eu posso melhorar o código para que este comentário não seja necessário?'
Antes do Java 5 a opção era usar constantes, algo como:
public class Usuario {
String nome;
String login;
String senha;
int perfil = Perfil.VISITANTE;
public abstract class Perfil {
public static final int VISITANTE = 0;
public static final int USUARIO = 1;
public static final int FUNCIONARIO = 2;
public static final int GERENTE = 3;
public static final int ADMINISTRADOR = 4;
}
}
O que já é bem mais profissional mesmo que não ofereça a segurança do enum. Digo isto por causa do benefício da tipagem forte, o que faz o Java uma opção para softwares robustos. Usando a implementação com constantes não há impedimento que alguém faça:
Usuario umUsuario = new Usuario();
umUsuario.perfil = 8;
Afinal, a variável perfil é do tipo inteiro. Claro que se encapsularmos a configuração do perfil em um setter (setPerfil(int perfil)) podemos tratar o número para que seja válido. Mas vamos um passo além, usaremos enums, como abaixo:
public class Usuario {
String nome;
String login;
String senha;
Perfil perfil = Perfil.VISITANTE;
public enum Perfil {
VISITANTE, USUARIO,
FUNCIONARIO, GERENTE,
ADMINISTRADOR;
}
}
Agora, a variável perfil é do tipo Perfil. Apenas os valores enumerados são aceitos, além de nulo é claro, pois o enumerado é um tipo (classe).
Sempre é preferível implementar utilizando a tipagem forte, que é bem viva no Java. A tipagem forte permite ver possíveis erros ainda em tempo de compilação e benefícia o código coletivo já que a intenção é declarada e a quantidade de valores aceitos é limitada. Seria diferente se usássemos Strings por exemplo, que é aberto a qualquer coisa.
Os níveis numéricos ainda podem ser obtidos, como no exemplo:
Usuario umUsuario = new Usuario();
umUsuario.perfil = Usuario.Perfil.GERENTE;
// mostra o índice
System.out.println(umUsuario.perfil.ordinal());
// mostra o nome
System.out.println(umUsuario.perfil.toString());
Simples não?
Outro caso comum é na passagem de parâmetros. Imagine um funcionário que é recuperado de um banco de dados e tem seu salário calculado assim:
Funcionario func = ds.findFuncionarioById(1288);
double salario = func.calculaSalario(3, true);
O que é 3? E o true? É para calcular de verdade? hehehe
Bem, teríamos que ver a assinatura do método para entender. Digamos que seja isto:
public double calculaSalario(int mes, boolean liquido) {
// implementação
}
Ah! O número é o mês e o true é para calcular liquido. False calcula o quê? Deve ser o salário bruto, eu acho.
Não preciso dizer que em programação não há espaço para achismo, então vamos implementar melhor este método usando o quê? usando o quê? ENUMS!
public class Funcionario {
public enum Mes {
JANEIRO, FEVEREIRO, MARCO, ABRIL, MAIO, JUNHO,
JULHO, AGOSTO, SETEMBRO, OUTUBRO, NOVEMBRO, DEZEMBRO;
}
public enum Valor {
LIQUIDO, BRUTO;
}
public double calculaSalario(Mes mes, Valor valor) {
// implementação
return 0.0;
}
}
Com esta implementação agora eu posso fazer:
Funcionario func = ds.findFuncionarioById(1288);
double salario = func.calculaSalario(Mes.MARCO, Valor.LIQUIDO);
Melhor?
Bem, mas digamos que ainda queira se manter a opção de passar o mês como inteiro. Note, usar tipos primitivos permitirá que seja passado qualquer valor, ou seja, algo como calculaSalario(15), bem propenso a erros. Também é o caso de querermos o número 1 para Janeiro, 2 para Fevereiro, etc, o que não é o caso quando chamamos ordinal() que começa com zero.
Então vamos preparar nosso enum para ser instanciado a partir de um inteiro para que faça a numeração correta:
public enum Mes {
JANEIRO(1), FEVEREIRO(2), MARCO(3), ABRIL(4),
MAIO(5), JUNHO(6), JULHO(7), AGOSTO(8),
SETEMBRO(9), OUTUBRO(10), NOVEMBRO(11), DEZEMBRO(12);
public int Numero;
Mes(int n) {
this.Numero = n;
}
public static Mes valueOf(int index) {
for (Mes mes : EnumSet.allOf(Mes.class)) {
if (mes.Numero == index) {
return mes;
}
}
return null;
}
}
O valor entre parênteses nos enumerados definem o enum passando o número no construtor. Assim sendo, se eu chamar Mes.JULHO.Numero retorna 7.
O método valueOf(int) devolve o enumerado adequado conforme o número, ou nulo se não for encontrado.
A implementação da chamada do método calculaSalario usando inteiros fica assim:
double salario = func.calculaSalario(Mes.valueOf(3), Valor.LIQUIDO);
Conclusão
Java é uma linguagem fortemente tipada e os programadores devem tirar proveito deste recurso que, naturalmente, faz do Java uma linguagem robusta, confiável e preferida por empresas de grande porte.