web-dev-qa-db-fra.com

Utilisation de types d'énumération imbriqués dans Java

J'ai une structure de données à l'esprit qui implique des énumérations imbriquées, de sorte que je puisse faire quelque chose comme ceci:

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

Et s'il y avait des déclarations de méthode:

someMethod(Drink type)
someOtherMethod(DrinkTypeInterface type)

Alors je pourrais dire (de façon appropriée):

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

Voici ce que j'ai trouvé:

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

Et l'interface:

public interface DrinkTypeInterface {

    public String getLabel();
}

Je pense que j'essaie simplement de comprendre ce que la meilleure façon de faire ce genre de chose est en Java, ou si j'ai besoin d'écrire un tas d'instructions if pour traiter les Drink.values ​​() individuelles. De l'aide?

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

Tout d'abord, cet exemple de code que vous avez donné viole quelque peu la "loi de déméter" - car le champ d'instance COLUMBIAN n'est utilisé que pour récupérer l'étiquette. De plus, avec cette structure, COLUMBIAN doit être une instance de l'énumération COFFEE, mais je ne pense pas que ce soit vraiment ce que vous recherchez ici.

someMethod(Drink type)
someOtherMethod(DrinkTypeInterface type)

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

Ce que je comprends de votre échantillon, c'est que vous voulez avoir une énumération qui contient un "type de groupe" de ce qu'est la boisson réelle, puis chacun a des valeurs individuelles pour le type spécifique de boisson. Votre exemple donne le café, mais le thé devrait tout aussi bien fonctionner.

Le problème est de savoir comment vous avez placé vos énumérations. Comme je l'ai déjà dit, il faudrait faire de COLUMBIAN une INSTANCE de l'énumération du CAFÉ, mais ce n'est pas vraiment la meilleure façon de structurer cela.

Le problème est que vous avez une boisson, puis un café/thé, puis leurs types individuels. Mais, si vous y pensez, bien que HerbalTea IS Un thé, c'est aussi une BOISSON - donc il n'appartient pas simplement à une instance de TEA.

Mais, si vous faites de la boisson type une énumération en soi, vous obtenez ce que vous vouliez, et la structure devient plus claire. Et en raison des interfaces et du pouvoir de délégation, le type de boisson et l'énumération de la boisson peuvent être traités de la même manière, comme avec l'exemple de programme suivant:

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

Le résultat de ce programme est le suivant:

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

Maintenant, si pour une raison quelconque vous ne vouliez pas toutes vos boissons dans un seul énum, ​​alors je ne comprenais pas ce que vous vouliez. Dans ce cas, si vous disposez de fonctionnalités qui couvrent les énumérations, effectuez des énumérations distinctes pour le café et le thé (et autres) et appliquez l'interface aux deux énumérations (ou plus). Mais je pense que vous essayiez de les regrouper comme ça.

36
MetroidFan2002

Pensez à utiliser EnumSet pour collecter différents types de Drink, comme suggéré ici .

Addendum: à titre d'exemple concret, le code ci-dessous produit la sortie affichée.

 Café: Columbian Blend 
 Café: Ethiopian Blend 

Code:

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

J'étais moi-même récemment curieux de savoir si cela pouvait être fait de manière quelque peu satisfaisante. C'est la solution que j'ai trouvée, dont l'API, je pense, correspond également plus à la structure arborescente des énumérations que le demandeur voulait à l'origine:

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
}
1
skoskav

vous pouvez faire quelque chose comme:

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