Duvida simples - Enum ou constante?

Bom dia amigos,

Resolvi postar aqui pois é um assunto relativamente simples, a que peço uma orientação. Estou desenvolvendo um projeto em que terei dois tipos de cliente, Pessoa Fisica e Pessoa Juridica. Da forma como o mesmo foi modelado, na base gravaríamos um campo para identificar cada um, com os valores “PF” ou “PJ”. Até aí tranquilo, hoje está tudo funcionando.

No objeto que abstrai o Cliente dentro do programa, há duas constantes:

    public static final String PESSOA_FISICA = "PF";
    public static final String PESSOA_JURIDICA = "PJ";

E todos os pontos onde isso é necessario ser tratado, sao usadas essas constantes. Nada anormal e tudo funciona.

Eu particularmente prefiro Enum a constantes em função da tipagem. Para esse caso, o Enum seria algo do tipo:

public enum TipoCliente
    PESSOA_FISICA ("PF"), PESSOA_JURIDICA ("PJ");

    private String value;

    private TipoCliente(String value){
        this.value = value;
    }
    public String getValue(){
        return value;
    }

Qual das duas formas os srs. consideram melhor?Ambas funcionam, claro…a alteração seria em função da clareza do código.

Com relação ao Enum, existiria alguma forma de ser criada uma instancia dele passando:

TipoCliente.valueOf("PF"); //vai dar xabu né? hehe

Obrigado.

  1. Use enum mesmo - você pode usar em switch, e em muitos lugares é possível tratá-los como se fossem inteiros (tradução: vão ser processados mais rapidamente).

  2. Para obter uma instância da enum TipoCliente por nome, use:

TipoCliente tc = Enum.valueOf (TipoCliente.class, "PESSOA_FISICA");

http://download-llnw.oracle.com/javase/6/docs/api/java/lang/Enum.html

Hum, não tinha visto que você queria achar o “PF”, não o “PESSOA_FISICA”. Eu fiz este exemplo aqui para inteiros (256, 720), troque a lógica para Strings (PF, PJ).

import java.util.*;

 enum ETipoFatura  {  
     POR_INTERVALO_DE_TEMPO(256),  
     POR_UNIDADE_REMOTA(720),  
     GERAL(840),  
     POR_INTERVALO_DE_TEMPO_UR(1023);  
   
     private final int value;  
   
     ETipoFatura(int value) {  
         this.value = value;  
     }  
   
     public int getValue() {  
         return value;  
     }
     private static final Map<Integer, ETipoFatura> value2enum = new HashMap<Integer, ETipoFatura>();
     static {
         for (ETipoFatura v : values()) {
             value2enum.put (v.getValue(), v);
         }
     }  
     public static ETipoFatura getInstance(int v) {
         return value2enum.get (v);
     }
 }  

class TesteEnum {
    public static void main(String[] args) {
        ETipoFatura etf = ETipoFatura.GERAL;
        ETipoFatura etf2 = ETipoFatura.getInstance (720);
        ETipoFatura etf3 = Enum.valueOf (ETipoFatura.class, "POR_INTERVALO_DE_TEMPO_UR");
        System.out.println (etf); // imprime GERAL
        System.out.println (etf.getValue()); // imprime 840
        System.out.println (etf2); // imprime POR_UNIDADE_REMOTA
        System.out.println (etf2.getValue()); // imprime 720
        System.out.println (etf3); // imprime POR_INTERVALO_DE_TEMPO_UR
        System.out.println (etf3.getValue()); // imprime 1023
    }    
}

Sem contar que, em enums, pode-se adicionar alguma lógica na própria enum (coisa que, com constantes, por mais que se possa otimizar uma lógica usando mapas ou algo assim, ainda fica mais lento).

[]´s

Obrigado. Não obstante as vantagens do Enum, é justamente essa lógica que eu não queria ter que fazer no Enum. Queria que o valueOf(String) resolvesse de alguma forma mágica e achasse o meu “PF” (que é o que vai ficar no banco e a partir desse valor vou criar o objeto). Mas ao menos no Enum só vai ser feito uma vez, enquanto com as constantes o codigo está cheio de ifs pra validar a String…

Obrigado, pessoal.

[quote=alias]Obrigado. Não obstante as vantagens do Enum, é justamente essa lógica que eu não queria ter que fazer no Enum. Queria que o valueOf(String) resolvesse de alguma forma mágica e achasse o meu “PF” (que é o que vai ficar no banco e a partir desse valor vou criar o objeto). Mas ao menos no Enum só vai ser feito uma vez, enquanto com as constantes o codigo está cheio de ifs pra validar a String…

Obrigado, pessoal.[/quote]

Mas a lógica são apenas 6 linhas na sua enum (mais umas chavinhas :slight_smile: ), e é igual para todas as enums que você for criar. Validar uma string (cujo processamento é infinitamente mais lento) em todos os pontos de seu código é uma “b…”. Se não for PF ou PJ, o getInstance vai retornar null; poderia até lançar uma exceção sua, derivada de RuntimeException, por exemplo.

      private static final Map<String, TipoCliente> value2enum = new HashMap<String, TipoCliente>();  
      static {  
          for (TipoCliente   v : values()) {  
              value2enum.put (v.getValue(), v);  
          }  
      }  
      public static TipoCliente getInstance(int v) {  
          return value2enum.get (v);  
      }  

[quote=asaudate]Sem contar que, em enums, pode-se adicionar alguma lógica na própria enum (coisa que, com constantes, por mais que se possa otimizar uma lógica usando mapas ou algo assim, ainda fica mais lento).

[]´s[/quote]

Sobre a lógica, se precisar ainda pode usar polimorfismo implementando interfaces.

Sim, já alterei para o Enum aqui e o que arranquei de if…rs. Já melhorou bastante a leitura.

Aproveitando o assunto:

Para retornar os meus “PF” e “PJ”, eu sobrescrevi o metodo toString(). Fiz isso pelo fato desse projeto utilizar JSF. Pelo que encontrei, na expression language, caso ocorra uma comparação usando o Enum, a interpretação da expressao vai invocar o toString() e depois comparar o valor. Isso procede? (ainda nao testei aqui…)

Assim ficou:

public enum TipoUsuario{
		PESSOA_FISICA("PF"), PESSOA_JURIDICA("PJ");
		
		private String value;
		
		private TipoUsuario(String value){
			this.value = value;
		}
		
		public static TipoUsuario create(String s){
			
			TipoUsuario t = null;
			
			if (s.equals("PF"))
				t = PESSOA_FISICA;
			else if (s.equals("PJ"))
				t = PESSOA_JURIDICA;
				
			return t;
		}
		
		@Override
		public String toString() {
			return value;
		}
	}

E no jsf, um exemplo:

<h:outputText rendered="#{meuBean.tipoUsuario == 'PF'}" />

E essa propriedade do meu managed-bean é do tipo TipoUsuario. Será que funciona? hehe

Obrigado.

[quote=alias]Sim, já alterei para o Enum aqui e o que arranquei de if…rs. Já melhorou bastante a leitura.

Aproveitando o assunto:

Para retornar os meus “PF” e “PJ”, eu sobrescrevi o metodo toString(). Fiz isso pelo fato desse projeto utilizar JSF. Pelo que encontrei, na expression language, caso ocorra uma comparação usando o Enum, a interpretação da expressao vai invocar o toString() e depois comparar o valor. Isso procede? (ainda nao testei aqui…)

Assim ficou:

public enum TipoUsuario{
		PESSOA_FISICA("PF"), PESSOA_JURIDICA("PJ");
		
		private String value;
		
		private TipoUsuario(String value){
			this.value = value;
		}
		
		public static TipoUsuario create(String s){
			
			TipoUsuario t = null;
			
			if (s.equals("PF"))
				t = PESSOA_FISICA;
			else if (s.equals("PJ"))
				t = PESSOA_JURIDICA;
				
			return t;
		}
		
		@Override
		public String toString() {
			return value;
		}
	}

E no jsf, um exemplo:

<h:outputText rendered="#{meuBean.tipoUsuario == 'PF'}" />

E essa propriedade do meu managed-bean é do tipo TipoUsuario. Será que funciona? hehe

Obrigado.[/quote]

Não funcionou, rs. O JSF usou o valueOf pra retornar o valor e fazer a comparação…ou seja, no jsf terei que usar

<h:outputText rendered="#{meuBean.tipoUsuario == 'PESSOA_FISICA'}" />

Ou criar um metodo no enum que retorno o tal do “PF”, de qualquer forma, há solução. Obrigado novamente, pessoal.

Complementando o caso do JSF:

<h:outputText rendered="#{meuBean.tipoUsuario eq 'PESSOA_FISICA'}" />

Obrigado.