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.