Usando tipos de enumeración anidados en Java
enums nested-class (4)
Tengo en mente una estructura de datos que involucra enumeraciones anidadas, de modo que podría hacer algo como lo siguiente:
Drink.COFFEE.getGroupName();
Drink.COFFEE.COLUMBIAN.getLabel();
Y si hubiera declaraciones de método:
someMethod(Drink type)
someOtherMethod(DrinkTypeInterface type)
Entonces podría decir (apropiadamente):
someMethod(Drink.COFFEE)
someOtherMethod(Drink.COFFEE.COLUMBIAN)
Esto es lo que se me ocurrió:
public enum Drink {
COFFEE("Coffee");
private String groupName;
private Drink(String groupName) {
this.groupName = groupName;
}
public enum Coffee implements DrinkTypeInterface {
COLUMBIAN("Columbian Blend"),
ETHIOPIAN("Ethiopian Blend");
private String label;
private Coffee(String label) {
this.label = label;
}
public String getLabel() {
return this.label;
}
}
String getGroupName() {
return this.groupName;
}
}
Y la interfaz:
public interface DrinkTypeInterface {
public String getLabel();
}
Creo que solo estoy tratando de comprender cuál es la mejor manera de hacer este tipo de cosas en Java, o si necesito escribir un montón de sentencias if para tratar con los Drink.values () individuales. ¿Alguna ayuda?
Considere usar EnumSet
para recolectar diferentes tipos de Drink
, como se sugiere here .
Addendum: Como ejemplo concreto, el siguiente código produce el resultado que se muestra.
Coffee: Columbian Blend Coffee: Ethiopian Blend
Código:
public static enum DrinkType {
COFFEE("Coffee"), TEA("Tea");
private final String displayName;
private DrinkType(final String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
public enum Drink {
COLUMBIAN(DrinkType.COFFEE, "Columbian Blend"),
ETHIOPIAN(DrinkType.COFFEE, "Ethiopian Blend"),
MINT_TEA(DrinkType.TEA, "Mint"),
HERBAL_TEA(DrinkType.TEA, "Herbal"),
EARL_GREY(DrinkType.TEA, "Earl Grey");
public static Set<Drink> coffees = EnumSet.of(COLUMBIAN, ETHIOPIAN);
public static Set<Drink> teas = EnumSet.range(MINT_TEA, EARL_GREY);
private String groupName;
private String drinkName;
private Drink(DrinkType type, String drinkName) {
this.groupName = type.getDisplayName();
this.drinkName = drinkName;
}
public String getGroupName() {
return this.groupName;
}
public String getDrinkName() {
return drinkName;
}
}
public static void main(String... args) {
for (Drink d : Drink.coffees) {
System.out.println(d.getGroupName() + ": " + d.getDrinkName());
}
}
Hace poco me pregunté si esto podría hacerse de manera algo satisfactoria. Esta es la solución con la que terminé, cuya API creo que también se asemeja más a la estructura de árbol de enumeraciones que originalmente quería el autor de la pregunta:
public interface Drink {
String groupName();
String label();
enum Coffee implements Drink {
COLUMBIAN("Columbian Blend"),
ETHIOPIAN("Ethiopian Blend");
private final String label;
Coffee(String label) {
this.label = label;
}
@Override
public String groupName() {
return "Coffee";
}
@Override
public String label() {
return label;
}
}
enum Tea implements Drink {
MINT("Mint"),
HERBAL("Herbal"),
EARL_GREY("Earl Grey");
private final String label;
Tea(String label) {
this.label = label;
}
@Override
public String groupName() {
return "Tea";
}
@Override
public String label() {
return label;
}
}
}
public static void main(String[] args) {
Drink choice = Drink.Tea.EARL_GREY;
System.out.println(choice.groupName()); // Tea
System.out.println(choice.label()); // Earl Grey
}
puedes hacer algo como:
enum dogs {
boxer, collie;
}
enum cats {
siamese, tom
}
enum Animal {
cat(cats.tom), dog(dogs.boxer);
Animal(Enum e) {
this.e = e;
}
Object[] subValues() {
return e.getDeclaringClass().getEnumConstants();
}
final Enum e;
}
public class Main {
public static void main(String[] args) {
for (Animal animal : Animal.values()) {
System.out.print(animal);
for (Object o : animal.subValues())
System.out.print(" " + o);
System.out.println();
}
}
}
Drink.COFFEE.getGroupName();
Drink.COFFEE.COLUMBIAN.getLabel();
En primer lugar, el código de muestra que dio viola la "ley de demeter" de alguna manera, ya que el campo de instancia de COLUMBIAN solo se usa para recuperar la etiqueta. Además, con esa estructura, COLUMBIAN tiene que ser una instancia de la enumeración de CAFÉ, pero no creo que eso sea lo que realmente está buscando aquí.
someMethod(Drink type)
someOtherMethod(DrinkTypeInterface type)
someMethod(Drink.COFFEE)
someOtherMethod(Drink.COFFEE.COLUMBIAN)
Lo que obtengo de lo que es su muestra es que desea tener una enumeración que contenga un "tipo de grupo" de lo que es la bebida real, y luego cada una tiene valores individuales para el tipo específico de bebida. Tu ejemplo da café, pero el té debería funcionar igual de bien.
El problema es cómo has colocado tus enumeraciones. Como dije antes, tendrías que hacer de COLUMBIAN una INSTANCIA de la enumeración de CAFÉ, pero esa no es realmente la mejor manera de estructurar esto.
El problema es que tienes bebida, luego café / té y luego sus tipos individuales. Pero, si lo piensas, aunque HerbalTea ES UN TÉ, también es una BEBIDA, por lo que no pertenece simplemente a una instancia de TEA.
Pero, si haces que la bebida escriba una enumeración en sí misma, obtienes lo que querías y la estructura se vuelve más clara. Y debido a las interfaces y al poder de delegación, tanto el tipo de bebida como la enumeración de la bebida se pueden procesar de la misma manera, como en el siguiente programa de ejemplo:
public final class DrinkEnumExample {
public interface DrinkTypeInterface {
String getDisplayableType();
}
public static enum DrinkType implements DrinkTypeInterface {
COFFEE("Coffee"), TEA("Tea");
private final String type;
private DrinkType(final String type) {
this.type = type;
}
public String getDisplayableType() {
return type;
}
}
public static enum Drink implements DrinkTypeInterface {
COLUMBIAN("Columbian Blend", DrinkType.COFFEE),
ETHIOPIAN("Ethiopian Blend", DrinkType.COFFEE),
MINT_TEA("Mint", DrinkType.TEA),
HERBAL_TEA("Herbal", DrinkType.TEA),
EARL_GREY("Earl Grey", DrinkType.TEA);
private final String label;
private final DrinkType type;
private Drink(String label, DrinkType type) {
this.label = label;
this.type = type;
}
public String getDisplayableType() {
return type.getDisplayableType();
}
public String getLabel() {
return label;
}
}
public DrinkEnumExample() {
super();
}
public static void main(String[] args) {
System.out.println("All drink types");
for (DrinkType type : DrinkType.values()) {
displayType(type);
System.out.println();
}
System.out.println("All drinks");
for (Drink drink : Drink.values()) {
displayDrink(drink);
System.out.println();
}
}
private static void displayDrink(Drink drink) {
displayType(drink);
System.out.print(" - ");
System.out.print(drink.getLabel());
}
private static void displayType(DrinkTypeInterface displayable) {
System.out.print(displayable.getDisplayableType());
}
}
La salida de este programa es la siguiente:
All drink types
Coffee
Tea
All drinks
Coffee - Columbian Blend
Coffee - Ethiopian Blend
Tea - Mint
Tea - Herbal
Tea - Earl Grey
Ahora bien, si por alguna razón no quisiste todas tus bebidas en una sola enumeración, entonces no entendí a qué te dirigías. En ese caso, si tiene una funcionalidad que abarca las enumeraciones, haga enumeraciones separadas de Café y Té (y lo que sea) y aplique la interfaz en ambas (o más) enumeraciones. Pero, creo que estabas tratando de agruparlos así.