2012-04-12 15 views
27

tengo la siguiente enumeración:enumeraciones compartían método estático de consulta

public enum MyEnum{ 
    A(10, "First"), // 
    B(20, "Second"), // 
    C(35, "Other options"); 

    private Integer code; 
    private String description; 

    private MyEnum(Integer code, String description) { 
     this.code = code; 
     this.description = description; 
    } 

    public Integer getCode() { 
     return code; 
    } 

    public String getDescription() { 
     return description; 
    } 

    public static MyEnum getValueOf(Integer code) { 
     for (MyEnum e : MyEnum.values()) { 
      if (e.getCode().equals(code)) { 
       return e; 
      } 
     } 
     throw new IllegalArgumentException("No enum const " + MyEnum.class.getName() + " for code \'" + code 
       + "\'"); 
    } 
} 

que funciona muy bien. El método getValueOf existe porque cuando nos comunicamos con un socio externo, solo obtenemos el código (que eligieron) para mapear. Necesito la descripción porque necesito mostrar una frase significativa en la GUI.

Pero ahora tengo un número de clases enum similares. Todos tienen su propia descripción de código &, y necesitan la misma funcionalidad de búsqueda. Quería que el método getValueOf fuera genérico, así que no necesito admitir más de 30 enumeraciones diferentes para básicamente el mismo método.

Para resolver esto, quería hacer una clase abstracta para definir este método e implementar algunas de las lógicas comunes, pero esto es imposible porque no puedo extender Enum.

Luego trató de hacer una clase de servicio con el siguiente método:

public static <T extends Enum<T>> T getValueOf(Enum<T> type, Integer code) {...} 

Pero los genéricos con enumeraciones son confusas y no entiendo cómo conseguir este trabajo.

Básicamente lo que quiero saber es: ¿Cuál es un buen enfoque para definir una utilidad común para una enumeración?

Respuesta

22

Debe pasar el objeto de la clase enum real como parámetro de su método. Luego puede obtener los valores enum usando Class.getEnumConstants().

Con el fin de poder acceder a la getCode() de los casos, debe definirlo en una interfaz y hacer todos sus tipos de enumeración implementan esa interfaz:

interface Encodable { 
    Integer getCode(); 
} 

public static <T extends Enum<T> & Encodable> T getValueOf(Class<T> enumClass, Integer code) { 
    for (T e : enumClass.getEnumConstants()) { 
     if (e.getCode().equals(code)) { 
      return e; 
     } 
    } 
    throw new IllegalArgumentException("No enum const " + enumClass.getName() + " for code \'" + code 
      + "\'"); 
} 

... 

public enum MyEnum implements Encodable { 
    ... 
} 

MyEnum e = getValueOf(MyEnum.class, 10); 
+0

FYI, el anterior podría arrojar un NPE si getCode devuelve nulo. Yo pondría un cheque en el condicional 'if' para null. –

+0

@JohnB, de hecho. Copié el código del OP y no me molesté en mejorarlo. En todo caso, en lugar de una verificación nula, cambiaría el tipo de 'código' por' int' para cortar el problema de raíz. –

+1

De hecho, tomé esto y lo incorporé en mi propio proyecto de utilidad. Hecho genérico 'Encodable' por lo que el método se convirtió' public static & Encodable > T getValueOf (Clase enumClass, código U) 'Espero que no te importe. –

7

Esto es un poco complicado ya que el método values() es estático. En realidad, necesitaría reflexión, pero hay una buena manera de ocultar esto utilizando la funcionalidad de biblioteca estándar.

En primer lugar, definir una interfaz con los métodos comunes a todos los tipos de enumeración:

public interface Common { 
    Integer getCode(); 
    String getDescription(); 
} 

A continuación, haz todas sus enumeraciones implementan esta interfaz:

public enum MyEnum implements Common {...} 

El método estático que desea tener entonces se parece a:

public static <T extends Enum<T> & Common> T getValueOf(Class<T> type, Integer code) { 
    final EnumSet<T> values = EnumSet.allOf(type); 
    for(T e : values) { 
     if(e.getCode().equals(code)) { 
      return e; 
     } 
    } 
    throw new IllegalArgumentException("No enum const " + type.getName() + " for code \'" + code + "\'"); 
} 
+0

Batido por 15 segundos, bueno.Lo único que cambiaría es usar 'getEnumConstants()' en lugar de crear un EnumSet, eso parece un poco inútil. – Voo

+0

@Voo Sí, casi la misma respuesta, pero no creo que mucha gente lo sepa de inmediato. ^^ Bueno, EnumSets son bastante eficientes, los gastos generales deberían ser bajos, pero no conocía este método para ser honesto. No veo la desventaja de usar 'getEnumConstants()', pero dejaré mi respuesta tal como está, porque todavía hay otra respuesta para usarla. –

+0

Tu comentario me desconcierta. ¿Ves una respuesta agregada por @Voo? ¿O a qué otra respuesta te refieres? –

Cuestiones relacionadas