Java中“枚举继承”的解决方案实现是什么?

3
前言:我已经研究过为什么Java中的“枚举继承”是不合法的。
我的问题如下:给定一个类“Recipe”,我希望它的属性“category”是一个常量值列表,例如“APPETIZER,BREAKFAST,DESSERT,MAIN_COURSE,SOUP” - 我使用枚举逻辑上可以实现这一点。
然后我的问题是:如果我想让每个枚举都有自己的“子项”(例如:对于“BREAKFAST”的“SWEET”和“SAVORY”,或者对于“DESSERT”的“CAKE”、“MUFFIN”和“BISCUITS”),以便:
1.指定子类(“子枚举”)是强制性的(例如,“myRecipe.setCategory(DESSERT)”应该引发异常);
2.禁止从不同“家族”的“子枚举”中使用(例如,“SOUP.BISCUITS”应该引发异常);
3.我应该能够通过点符号访问“子枚举”(例如,“myRecipe.setCategory(DESSERT.CAKE)”) - 或其他类似的“轻量级”语法。
我还没有能够想出任何在Java中实现所有三个要求的“干净”解决方案。
是否有任何“神秘的”设计模式来解决这个问题?你会如何实现这个问题?

你会如何持久地存储分类?也许可以将它们作为具有ID、名称和可选父ID的分类集合来存储。这将强制实施层次结构。您还可以禁止选择父ID为空的类别,从而实现所需的子类别选择。 - John Glenn
理想情况下,您的代码不需要在代码中硬编码类别结构。如果您需要这样做,我建议为IRecipeCategory创建一个实现适当的getter和setter的接口。然后,在每个类别下嵌套子类别,为每个类别创建一个类。通过所有类别/子类别实现该接口,您的.setCategory方法可以接受其中任何一个。 - John Glenn
2个回答

1

简单设计

创建一个类Category。在Category内部,声明所有的枚举类。

public class Category
{
    public enum APPETIZER
    {
    }

    public enum BREAKFAST
    {
        SWEET,
        SAVORY
    }

    public enum DESSERT
    {
        CAKE,
        MUFFIN,
        BISCUITS
    }

    public enum MAIN_COURSE
    {
    }
}

Recipe类中,category应该是DESSERT类型。我已经静态导入了Category类。
public class Recipe
{
    DESSERT category;

    public void setCategory(DESSERT category)
    {
        this.category = category;
    }

    public static void main(String[] args)
    {
        Recipe myRecipe = new Recipe();

        myRecipe.setCategory(DESSERT.BISCUITS);

        // statements below give compile time errors
        // myRecipe.setCategory(DESSERT);
        // myRecipe.setCategory(BREAKFAST.SWEET);
    }
}

改进

类别(Category)转换为标记接口。所有类别,如DESSERTBREAKFAST等,都应该实现Category接口。

interface Category {}

enum APPETIZER implements Category 
{
}

enum BREAKFAST implements Category
{
    SWEET,
    SAVORY
}

enum DESSERT implements Category
{
    CAKE,
    MUFFIN,
    BISCUITS
}

enum MAIN_COURSE implements Category
{
}


使Recipe通用化。
public class Recipe <T extends Category>
{
     T category;

    public void setCategory(T category)
    {
        this.category = category;
    }

    public static void main(String[] args)
    {
        Recipe<DESSERT> myRecipe = new Recipe<>();

        myRecipe.setCategory(DESSERT.BISCUITS);

        // statements below give compile time errors
        // myRecipe.setCategory(DESSERT);
        // myRecipe.setCategory(BREAKFAST.SWEET);
    }
}

这些不是设计模式。它们是自我实现。

1
你可以这样做:
class Recipe {
    private final Meal meal;
    private final MealCategory category;

    public <T extends Meal> Recipe(T meal, MealCategory<T> category) {
        this.meal = meal;
        this.category = category;
    }
}
abstract class Meal {}
class Breakfast extends Meal {}
class Dinner extends Meal {}

class MealCategory<T extends Meal> {}

class Cereal extends MealCategory<Breakfast> {}
class Meat extends MealCategory<Dinner> {}

public class Test {

    public static void main(String[] args) {
        Recipe r = new Recipe(new Breakfast(), new Cereal());
        Recipe r2 = new Recipe(new Breakfast(), new Meat()); // compile time error
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接