Preface: I've already researched why "enum inheritance" is illegal in Java.
My problem is the following: given a class Recipe, I want its property category to be a list of constant values like APPETIZER, BREAKFAST, DESSERT, MAIN_COURSE, SOUP - I logically use enums for this.
My question then is: if I wanted each of this enums to have "children of their own" (for example: SWEET and SAVORY for BREAKFAST, or CAKE, MUFFIN and BISCUITS for DESSERT), so that:
- Specifying the subcategory ("child enum") is mandatory (e.g.
myRecipe.setCategory(DESSERT)should raise an exception); - Using a "child enum" from a different "family" is forbidden (e.g.
SOUP.BISCUITSshould raise an exception); - I should be able to access the "child enum" through dot notation (e.g.
myRecipe.setCategory(DESSERT.CAKE)) - or other similar "lightweight" syntax.
I haven't been able to come up with any clean solution in Java to fit all three requisites.
Is there any "esoteric" design pattern for this? How would you implement this?
CodePudding user response:
You can do this:
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
}
}
CodePudding user response:
Simple Design
Create a class Category. Inside Category, declare all the enum classes.
public class Category
{
public enum APPETIZER
{
}
public enum BREAKFAST
{
SWEET,
SAVORY
}
public enum DESSERT
{
CAKE,
MUFFIN,
BISCUITS
}
public enum MAIN_COURSE
{
}
}
Inside the Recipe class, category should be of type DESSERT. I have static imported Category class.
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);
}
}
Improvement
Convert Category into a marker interface. All the categories such as DESSERT, BREAKFAST, etc. should implement 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
{
}
Make Recipe generic.
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);
}
}
These are not design patterns. They are self implementation.
