在 Java 中使用嵌套枚举类型

发布于 2024-12-02 17:28:53 字数 1142 浏览 0 评论 0 原文

我脑子里有一个涉及嵌套枚举的数据结构,这样我就可以做类似以下的事情:

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

如果有方法声明:那么

someMethod(Drink type)
someOtherMethod(DrinkTypeInterface type)

我可以(适当地)说:

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

这就是我想出的:

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

以及接口:

public interface DrinkTypeInterface {

    public String getLabel();
}

我我想我只是想弄清楚在 Java 中做这类事情的最佳方法是什么,或者我是否需要编写一堆 if 语句来处理单个 Drink.values()。有什么帮助吗?

I have a data structure in mind that involves nested enums, such that I could do something like the following:

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

And if there were method declarations:

someMethod(Drink type)
someOtherMethod(DrinkTypeInterface type)

Then I could say (appropriately):

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

This is what I came up with:

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

And the interface:

public interface DrinkTypeInterface {

    public String getLabel();
}

I think I'm just trying to wrap my head around what the best way to do this sort of thing is in Java, or if I need to write a bunch of if-statements to deal with the individual Drink.values(). Any help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我的黑色迷你裙 2024-12-09 17:28:53
Drink.COFFEE.getGroupName();
Drink.COFFEE.COLUMBIAN.getLabel();

首先,您提供的示例代码在某种程度上违反了“德米特定律” - 因为 COLUMBIAN 实例字段仅用于检索标签。另外,通过该结构,COLUMBIAN 必须是 COFFEE 枚举的一个实例,但我认为这并不是您真正想要的。

someMethod(Drink type)
someOtherMethod(DrinkTypeInterface type)

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

我从你的样本中收集到的是,你想要一个包含实际饮料的“组类型”的枚举,然后每个类型都有特定类型饮料的单独值。你的例子给出了咖啡,但茶也应该同样有效。

问题在于您如何放置枚举。正如我之前所说,您必须使 COLUMBIAN 成为 COFFEE 枚举的实例,但这实际上并不是构建此枚举的最佳方法。

问题是你有饮料,然后是咖啡/茶,然后是它们各自的类型。
但是,如果您想一想,虽然草茶是一种茶,但它也是一种饮料 - 因此它不只是茶的一个实例。

但是,如果您使饮料类型本身成为一个枚举,您就会得到您想要的东西,并且结构会变得更加清晰。并且由于接口和委托的力量,饮料类型和饮料枚举都可以以相同的方式处理,如以下示例程序所示:

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

该程序的输出如下:

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

现在,如果由于某种原因您不希望你所有的饮料都在一个枚举中,那么我就不明白你想要什么。在这种情况下,如果您确实具有跨越枚举的功能,请单独进行咖啡和茶(以及其他)枚举,并将接口应用于两个(或多个)枚举。但是,我认为你试图像这样将它们分组。

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

First off, that sample code you gave violates the "law of demeter" somewhat - as the COLUMBIAN instance field is only used to retrieve the label. Also, with that structure, COLUMBIAN has to be an instance of the COFFEE enum, but I don't think that's what you're really going for here.

someMethod(Drink type)
someOtherMethod(DrinkTypeInterface type)

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

What I'm gathering from what your sample is, is that you want to have an enumeration that contains a "group type" of what the actual drink is, and then each one has individual values for the specific type of drink. Your example gives Coffee, but Tea should work just as well.

The problem is how you've placed your enumerations. As I said before, you'd have to make COLUMBIAN an INSTANCE of the COFFEE enumeration, but that's not really the best way to structure this.

The problem is that you've got Drink, then Coffee/Tea, and then their individual types.
But, if you think about it, although HerbalTea IS A Tea, it is also a DRINK - so it doesn't belong as simply an instance of a TEA.

But, if you make the drink type an enum in and of itself, you get what you wanted, and the structure becomes clearer. And due to interfaces and the power of delegation, both the drink type and the drink enum can be processed in the same manner, as with the following example program:

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

The output of this program is as follows:

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

Now then, if for some reason you didn't want all your drinks in a single enum, then I didn't understand what you were going for. In that case, if you do have functionality that spans the enums, make separate Coffee and Tea (and whatever) enumerations and apply the interface on both (or more) enumerations. But, I think you were trying to group them like this.

千笙结 2024-12-09 17:28:53

考虑使用 EnumSet 按照建议饮料 href="https://stackoverflow.com/questions/6559163/stopping-repetition-in-java-enums/6559541#6559541">此处。

附录:作为一个具体示例,下面的代码产生所示的输出。

Coffee: Columbian Blend
Coffee: Ethiopian Blend

代码:

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

Consider using EnumSet to collect different types of Drink, as suggested here.

Addendum: As a concrete example, the code below produces the output shown.

Coffee: Columbian Blend
Coffee: 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());
    }
}
暮年 2024-12-09 17:28:53

我最近很好奇这是否可以做得令人满意。这是我最终得到的解决方案,我认为其 API 也更接近提问者最初想要的枚举树结构:

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
}

I was recently curious myself if this could be done somewhat satisfactorily. This is the solution I ended up with, whose API I think also closer matches the tree structure of enums that the asker originally wanted:

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
}
┾廆蒐ゝ 2024-12-09 17:28:53

你可以这样做:

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

you can do something like:

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();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文