Utilizzo di tipi enumerati nidificati in Java

Ho in mente una struttura di dati che implica enumerazioni annidate, in modo tale da poter fare qualcosa di simile al seguente:

Drink.COFFEE.getGroupName(); Drink.COFFEE.COLUMBIAN.getLabel(); 

E se ci fossero dichiarazioni di metodo:

 someMethod(Drink type) someOtherMethod(DrinkTypeInterface type) 

Quindi potrei dire (appropriatamente):

 someMethod(Drink.COFFEE) someOtherMethod(Drink.COFFEE.COLUMBIAN) 

Questo è quello che mi è venuto in mente:

 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; } } 

E l’interfaccia:

     public interface DrinkTypeInterface { public String getLabel(); } 

    Penso che sto solo cercando di capire quale sia il modo migliore per fare questo genere di cose in Java, o se ho bisogno di scrivere una serie di istruzioni if ​​per affrontare il singolo Drink.values ​​(). Qualsiasi aiuto?

     Drink.COFFEE.getGroupName(); Drink.COFFEE.COLUMBIAN.getLabel(); 

    Prima di tutto, quel codice di esempio che hai dato viola la “legge del demeter” in qualche modo – poiché il campo dell’istanza COLUMBIAN viene utilizzato solo per recuperare l’etichetta. Inoltre, con questa struttura, COLUMBIAN deve essere un’istanza dell’enumerazione COFFEE, ma non penso che questo sia ciò che stai realmente facendo qui.

     someMethod(Drink type) someOtherMethod(DrinkTypeInterface type) someMethod(Drink.COFFEE) someOtherMethod(Drink.COFFEE.COLUMBIAN) 

    Quello che sto raccogliendo da ciò che il tuo campione è, è che vuoi avere un’enumerazione che contiene un “tipo di gruppo” di ciò che è la bevanda reale, e quindi ognuno ha valori individuali per il tipo specifico di bevanda. Il tuo esempio dà il caffè, ma il tè dovrebbe funzionare altrettanto bene.

    Il problema è come hai inserito le tue enumerazioni. Come ho detto prima, dovresti rendere COLUMBIAN un’istanza dell’enumerazione COFFEE, ma non è davvero il modo migliore per strutturarlo.

    Il problema è che hai Drink, poi Caffè / Tè e poi i loro singoli tipi. Ma, se ci pensate, anche se HerbalTea è un tè, è anche una bevanda – quindi non appartiene semplicemente come un’istanza di un tè.

    Ma se fai bere alla bevanda un enum in sé e per sé, ottieni quello che volevi e la struttura diventa più chiara. E a causa delle interfacce e del potere di delega, sia il tipo di bevanda che l’enumerazione di bevande possono essere elaborati nello stesso modo, come nel seguente esempio di programma:

     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()); } } 

    L’output di questo programma è il seguente:

     All drink types Coffee Tea All drinks Coffee - Columbian Blend Coffee - Ethiopian Blend Tea - Mint Tea - Herbal Tea - Earl Grey 

    Ora poi, se per qualche motivo non volevi tutti i tuoi drink in una singola enum, allora non capivo cosa stavi cercando. In tal caso, se si dispone di funzionalità che coprono l’enumerazione, effettuare Coffee Enotations separati (e qualsiasi altra cosa) e applicare l’interfaccia su entrambe (o più) enumerazioni. Ma, penso che stavi cercando di raggrupparli in questo modo.

    Considerare l’utilizzo di EnumSet per raccogliere diversi tipi di Drink , come suggerito qui .

    Addendum: come esempio concreto, il codice sottostante produce l’output mostrato.

     Caffè: Columbian Blend
     Caffè: miscela etiopica
    

    Codice:

     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 coffees = EnumSet.of(COLUMBIAN, ETHIOPIAN); public static Set 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()); } } 

    puoi fare qualcosa come:

     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(); } } } 

    Recentemente mi sono incuriosito se questo potesse essere fatto in modo soddisfacente. Questa è la soluzione alla quale mi sono ritrovato, la cui API mi sembra anche più vicina alla struttura ad albero delle enumerazioni che il richiedente voleva originariamente:

     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 }