Использование вложенных типов перечислений в 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 (). Любая помощь?
4 ответа
Drink.COFFEE.getGroupName();
Drink.COFFEE.COLUMBIAN.getLabel();
Во-первых, этот пример кода, который вы дали, несколько нарушает "закон деметры" - поскольку поле экземпляра COLUMBIAN используется только для получения метки. Кроме того, с этой структурой COLUMBIAN должен быть экземпляром перечисления COFFEE, но я не думаю, что это то, для чего вы здесь действительно собираетесь.
someMethod(Drink type)
someOtherMethod(DrinkTypeInterface type)
someMethod(Drink.COFFEE)
someOtherMethod(Drink.COFFEE.COLUMBIAN)
Из того, что вы делаете, я собираю то, что вы хотите иметь перечисление, которое содержит "групповой тип" того, что представляет собой фактический напиток, а затем каждый из них имеет индивидуальные значения для определенного типа напитка. Ваш пример дает кофе, но чай должен работать так же хорошо.
Проблема в том, как вы разместили свои перечисления. Как я уже говорил, вы должны сделать COLUMBIAN МОМЕНТОМ перечисления КОФЕ, но это не самый лучший способ структурировать это.
Проблема в том, что у вас есть напиток, затем кофе / чай, а затем их отдельные типы. Но, если подумать, хотя HerbalTea - это чай, это еще и напиток - поэтому он не является просто экземпляром ЧАЯ.
Но если вы сделаете напиток типом enum сам по себе, вы получите то, что хотели, и структура станет более ясной. А благодаря интерфейсам и полномочиям делегирования и тип напитка, и перечисление напитка могут обрабатываться таким же образом, как и в следующем примере программы:
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
Итак, если по какой-то причине вы не хотите, чтобы все ваши напитки были в одном перечислении, тогда я не поняла, для чего вы собираетесь. В этом случае, если у вас есть функциональные возможности, охватывающие перечисления, создайте отдельные перечисления 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<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());
}
}
Недавно мне стало любопытно, можно ли это сделать несколько удовлетворительно. На этом я остановился на решении, 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
}
Вы можете сделать что-то вроде:
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();
}
}
}