一、枚举类型——使用接口来组织枚举

枚举类型无法被继承,这一点可能有时会让人沮丧。想要继承枚举的动机,一部分源自希望扩充原始枚举中的元素,另一部分源自想要使用子类型来创建不同的子分组。

你可以在一个接口内对元素进行分组,然后基于这个接口生成一个枚举,通过这样的方式来实现元素的分类。举个例子,假如你有一些类型互不相同的 food (食物),想创建若干 enum 来组织它们,但又希望它们仍然是 Food 类型,你可以这么做:

Food.java

public interface Food {
    enum Appetizer implements Food {
        SALAD, SOUP, SPRING_ROLLS;
    }

    enum MainCourse implements Food {
        LASAGNE, BURRITO, PAD_THAI,
        LENTILS, HUMMUS, VINDALOO;
    }

    enum Dessert implements Food {
        TIRAMISU, GELATO, BLACK_FOREST_CAKE,
        FRUIT, CREME_CARAMEL;
    }

    enum Coffee implements Food {
        BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
        LATTE, CAPPUCCINO, TEA, HERB_TEA;
    }
}

实现接口是唯一可子类化枚举的方式,因此所有嵌套在 Food 中的枚举类型都实现了 Food 接口。现在我们基本可以说“ 一切都是某种类型的Food”,如下例所示:

TypeOfFood.JAVA

import enums.TEST0522.Food.*;

public class TypeOfFood {
    public static void main(String[] args) {
        Food food = Appetizer.SALAD;
        food = MainCourse.LASAGNE;
        food = Dessert.GELATO;
        food = Coffee.CAPPUCCINO;
    }
}

对于每个实现了 Food 接口的枚举类型,都可以向上转型为 Food ,因此它们全都是 Food 类型 。

但是,当你要处理一组类型时,接口往往就不如枚举有用。如果要创建“由枚举组成的枚举”,你可以为 Food 中的每个枚举类型都创建一个外部枚挙类型:

Course.java

public enum Course {
    APPETIZER(Food.Appetizer.class),
    MAINCOURSE(Food.MainCourse.class),
    DESSERT(Food.Dessert.class),
    COFFEE(Food.Coffee.class);
    private Food[] values;

    private Course(Class<? extends Food> kind) {
        values = kind.getEnumConstants();
    }

    public Food randomSelection() {
        return Enums.random(values);
    }
}

上面的代码中,每个枚举类型都接收相应的 Class 对象以作为构造参数,从而可以使用 getEnumConstants() 来提取出所有的枚举实例并存储起来,这些实例稍后会在 randomselection() 中被用到。好了,现在我们可以从每个 Course (菜项,如“ 前菜/主菜/ 甜点”)中选择一种 Food (食物),生成一份随机配好的午餐了。

Meal.java

public class Meal {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            for (Course course : Course.values()) {
                Food food = course.randomSelection();
                System.out.println(food);
            }
            System.out.println("***");
        }
    }
}

运行结果如下:
一、枚举类型——使用接口来组织枚举_第1张图片

此处,创建一个由枚举类型组成的枚举类型的意义在于,可以方便地遍历每个 Course。在稍后的例子 VendingMachine.java 中,你会看到另一种由不同约束条件指定的分类方法。

另一种更简洁的分类方法是在枚举内嵌套枚举,如下例所示:

SecurityCategory.java

enum SecurityCategory {
    STOCK(Security.Stock.class),
    BOND(Security.Bond.class);
    Security[] values;

    SecurityCategory(Class<? extends Security> kind) {
        values = kind.getEnumConstants();
    }

    interface Security {
        enum Stock implements Security {
            SHORT, LONG, MARGIN
        }

        enum Bond implements Security {
            MUNICIPAL, JUNK
        }
    }

    public Security randomSelection() {
        return Enums.random(values);
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            SecurityCategory category = Enums.random(SecurityCategory.class);
            System.out.println(category + ": " + category.randomSelection());
        }
    }
}

运行结果如下:
一、枚举类型——使用接口来组织枚举_第2张图片

Security接口用于将内部的枚举类型作为公共类型聚合到一起,然后再将它们归类到
SecurityCategory 中的枚举中。

如果将此方法应用到前面的Food示例,那么结果如下:

Meal2.java

public enum Meal2 {
    APPETIZER(Food.Appetizer.class),
    MAINCOURSE(Food.MainCourse.class),
    DESSERT(Food.Dessert.class),
    COFFEE(Food.Coffee.class);
    private Food[] values;

    private Meal2(Class<? extends Food> kind) {
        values = kind.getEnumConstants();
    }

    public interface Food {
        enum Appetizer implements Food {
            SALAD, SOUP, SPRING_ROLLS;
        }

        enum MainCourse implements Food {
            LASAGNE, BURRITO, PAD_THAI,
            LENTILS, HUMMUS, VINDALOO;
        }

        enum Dessert implements Food {
            TIRAMISU, GELATO, BLACK_FOREST_CAKE,
            FRUIT, CREME_CARAMEL;
        }

        enum Coffee implements Food {
            BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
            LATTE, CAPPUCCINO, TEA, HERB_TEA;
        }
    }

    public Food randomSelection() {
        return Enums.random(values);
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            for (Meal2 meal : Meal2.values()) {
                Food food = meal.randomSelection();
                System.out.println(food);
            }
            System.out.println("***");
        }
    }
}

运行结果如下:
一、枚举类型——使用接口来组织枚举_第3张图片

最后,虽然这只是对代码重新组织了一下,但在某些情况下,这样可以使结构更加清晰。

你可能感兴趣的:(#,On,Java,进阶卷,枚举类型,使用接口来组织枚举)