代码重用:使用常见的 getter 方法返回枚举字段列表

fri*_*ode 6 java methods enums field dry

我有两个枚举:

主菜单选项

public enum MainMenuOptions {
    
    EXIT("Exit"),
    VIEW_RESERVATIONS("View Reservations By Host"),
    CREATE_RESERVATION("Create A Reservation"),
    EDIT_RESERVATION("Edit A Reservation"),
    CANCEL_RESERVATION("Cancel A Reservation");
    
    private final String message;
    
    MainMenuOptions(String message) {
        this.message = message;
    }
    
    public String getMessage() {
        return message;
    }
    
    public static List<String> asListString() {
        return Arrays.stream(MainMenuOptions.values())
                .map(MainMenuOptions::getMessage)
                .collect(Collectors.toList());
    }
}
Run Code Online (Sandbox Code Playgroud)

主机选择方法选项

public enum HostSelectionMethodOptions {
    
    FIND_ALL("Find all"),
    FIND_BY_LASTNAME_PREFIX("Find by last name prefix"),
    FIND_BY_CITY_STATE("Find by city & state");
    
    String message;
    
    HostSelectionMethod(String message) {
        this.message = message;
    }
    
    public String getMessage() {
        return message;
    }
    
    public static List<String> asListString() {
        return Arrays.stream(HostSelectionMethod.values())
                .map(HostSelectionMethod::getMessage)
                .collect(Collectors.toList());
    }
}
Run Code Online (Sandbox Code Playgroud)

两个枚举共享相同的字段

private final String message;
Run Code Online (Sandbox Code Playgroud)

相同的吸气剂

public String getMessage() {
    return message;
}
Run Code Online (Sandbox Code Playgroud)

与asListString()方法相同

public static List<String> asListString() {
    return Arrays.stream(MainMenuOptions.values())
            .map(MainMenuOptions::getMessage)
            .collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能干燥这些枚举?

我希望有更多具有相同字段和方法的枚举,并且为每个枚举一遍又一遍地写出相同的内容似乎很愚蠢。

  • 我尝试使两个枚举都扩展为超类,但枚举不能具有扩展子句
  • 我可以创建一个接口来指定 asListString() 方法的约定,但这不允许我实际重用任何代码。

我希望代码的风格是这样的:

public class Utils {
    
    public static List<String> enumAsListString(Enum e) {
        return e.values().stream.map(e::getMessage).collect(Collectors.toList());
    }
}
Run Code Online (Sandbox Code Playgroud)

ern*_*t_k 2

这可能是您需要在 DRY 和使用枚举之间进行选择的情况之一。

就代码重用而言,枚举并没有走得太远,至少在 Java 中是这样;其主要原因是使用枚举的主要好处是在静态代码中获得的 - 我的意思是“非动态”/“运行时”中的静态,而不是static:)。虽然您可以“减少”代码重复,但如果不引入依赖项,您几乎无法做到这一点(是的,这适用于添加通用 API/接口,将实现提取到asListString实用程序类)。这仍然是一个不受欢迎的权衡。

此外,如果您必须使用枚举(出于对序列化、数据库映射、JSON 绑定的内置支持等原因,或者,因为它是数据枚举等),您别无选择,只能将方法声明复制到在某种程度上,即使您可以共享实现:静态方法不能被继承,并且接口方法(其中之一getMessage)应该在任何地方都需要实现。我的意思是,这种“干”的方式有很多不优雅的方式。

如果我是你,我会让这些数据完全动态化

final class MenuOption {
    private final String category; //MAIN_MENU, HOT_SELECTION
    private final String message; //Exit, View Reservation By Host, etc.
    public static MenuOption of(String key, String message) {
        return new MenuOption(key, message);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是非常可扩展的,尽管它需要验证数据,其中枚举将静态地防止错误选项,并且可能需要验证自定义代码,其中枚举将提供内置支持。

它可以通过“类别”枚举来改进,它提供对菜单列表的静态访问,以及一个位置asListString()

enum MenuCategory {
    MAIN_MENU(
        MenuOption.of("Exit"), 
        MenuOption.of("View Reservations By Host")
    ),
    HOT_SELECTION(
        MenuOption.of("Find All")
    );
    
    private final List<MenuOption> menuOptions;
    
    MenuCategory(MenuOption... options) {
        this.menuOptions = List.of(options); //unmodifiable
    }
    
    public List<String>asListString() {
        return this.menuOptions.stream()
                   .map(MenuOption::getMessage)
                   .collect(Collectors.toList());
    }
}
Run Code Online (Sandbox Code Playgroud)

很明显,您可以class MenuOption用一堆实现通用接口的枚举来替换,这在MenuCategory. 我不会这样做,但这是一个选择。