在Java中使用嵌套的枚举类型

我有一个涉及嵌套枚举的数据结构,这样我就可以执行以下操作:

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()。 有帮助吗?

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

首先,您提供的示例代码在某种程度上违反了“demeter法则” – 因为COLUMBIAN实例字段仅用于检索标签。 此外,有了这个结构,COLUMBIAN 必须是COFFEE enum的一个实例,但我不认为这就是你真正想要的。

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

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

问题是你如何放置你的枚举。 正如我之前所说的那样,你必须让COLUMBIAN成为COFFEE枚举的实例,但这并不是构建它的最好方法。

问题是你有饮料,然后是咖啡/茶,然后是各自的类型。 但是,如果你考虑一下,虽然HerbalTea是一种茶,它也是一种饮品 – 所以它不仅仅是TEA的一个例子。

但是,如果你让饮料类型成为一个枚举,你得到你想要的东西,结构变得更加清晰。 并且由于界面和授权的强大,饮料类型和饮料枚举都可以以相同的方式处理,如下面的示例程序:

 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 

现在,如果由于某种原因你不想把所有的饮料都放在一个枚举中,那么我就不明白你的意思了。 在这种情况下,如果您确实具有跨越枚举的function,请制作单独的Coffee和Tea(以及其他)枚举,并在两个(或更多)枚举上应用该接口。 但是,我认为你试图像这样分组他们。

考虑使用EnumSet来收集不同类型的Drink ,如此处所示 。

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

咖啡:哥伦比亚混合
咖啡:埃塞俄比亚混合

码:

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

你可以这样做:

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

我最近好奇自己是否可以做得有些令人满意。 这是我最终得到的解决方案,我认为其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 }