代码重用:使用常用 getter 方法返回枚举字段列表
Code reuse: returning lists of enum fields with common getter methods
我有两个枚举:
主菜单选项
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());
}
}
主机选择方法选项
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());
}
}
两个枚举共享同一个字段
private final String message;
一样getter
public String getMessage() {
return message;
}
与ListString()方法相同
public static List<String> asListString() {
return Arrays.stream(MainMenuOptions.values())
.map(MainMenuOptions::getMessage)
.collect(Collectors.toList());
}
我怎样才能干掉这些枚举?
我希望有更多具有相同字段和方法的枚举,并且为每个枚举一遍又一遍地写出相同的东西似乎很愚蠢。
- 我尝试让两个枚举都扩展一个超类,但是枚举不能有扩展子句
- 我可以创建一个接口来指定 asListString() 方法的约定,但这不允许我实际重用任何代码。
我希望代码的风格是这样的:
public class Utils {
public static List<String> enumAsListString(Enum e) {
return e.values().stream.map(e::getMessage).collect(Collectors.toList());
}
}
这可能是您需要在 DRY 和使用枚举之间做出选择的情况之一。
就代码重用而言,枚举并没有走得太远,至少在 Java 中是这样;这样做的主要原因是使用枚举的主要好处是在静态代码中获得——我的意思是 static 作为“非动态”/“运行时”,而不是 static
:).尽管您可以“减少”代码重复,但如果不引入依赖性(是的,这适用于添加通用 API/interface,将 asListString
的实现提取到实用程序 class).这仍然是一个不受欢迎的权衡。
此外,如果您必须使用枚举(出于对序列化、数据库映射、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);
}
}
这是非常可扩展的,尽管它引入了验证数据的需要,其中枚举将静态地防止错误的选项,并且可能需要自定义代码,其中枚举将提供内置支持。
它可以通过“类别”枚举进行改进,它提供对菜单列表的静态访问,以及 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());
}
}
应该清楚的是,您可以用一堆实现通用接口的枚举替换 class MenuOption
,这在 MenuCategory
中应该几乎没有变化。我不会那样做,但这是一个选择。
你可以稍微晾干一下。
Utils.java
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public interface Utils<T>
{
public String getMessage();
public static <T extends Utils<T>> List<String> asListString(Class<T> clazz)
{
return Arrays.stream(clazz.getEnumConstants())
.map(T::getMessage)
.collect(Collectors.toList());
}
}
HostSelectionMethodOptions.java
public enum HostSelectionMethodOptions implements Utils<HostSelectionMethodOptions> {
FIND_ALL("Find all"),
FIND_BY_LASTNAME_PREFIX("Find by last name prefix"),
FIND_BY_CITY_STATE("Find by city & state");
private final String message;
HostSelectionMethodOptions(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
然后就这样做 - Utils.asListString(HostSelectionMethodOptions.class);
我和davidalayachew的想法基本一样
一个枚举可以实现一个接口。因此,如果您创建一个接受 enum
类型的通用 asListString
,您可以获得所需的结果。
首先,创建一个 Options
接口并让两个 enum
实现它:
interface Options {
String getMessage();
}
enum HostSelectionMethodOptions implements Options { ... }
enum MainMenuOptions implements Options { ... }
现在创建一个这样的方法:
public static <T extends Enum<T> & Options> List<String> asListString(Class<T> type) {
return Arrays.stream(type.getEnumConstants())
.map(T::getMessage)
.collect(Collectors.toList());
}
该方法声明了一个类型参数:<T extends Enum<T> & Options>
。这里,T
是一个 交集类型 ,因此它扩展了 Enum
和 Options
接口。你可以这样称呼它:
asListString(MainMenuOptions.class);
我有两个枚举:
主菜单选项
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());
}
}
主机选择方法选项
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());
}
}
两个枚举共享同一个字段
private final String message;
一样getter
public String getMessage() {
return message;
}
与ListString()方法相同
public static List<String> asListString() {
return Arrays.stream(MainMenuOptions.values())
.map(MainMenuOptions::getMessage)
.collect(Collectors.toList());
}
我怎样才能干掉这些枚举?
我希望有更多具有相同字段和方法的枚举,并且为每个枚举一遍又一遍地写出相同的东西似乎很愚蠢。
- 我尝试让两个枚举都扩展一个超类,但是枚举不能有扩展子句
- 我可以创建一个接口来指定 asListString() 方法的约定,但这不允许我实际重用任何代码。
我希望代码的风格是这样的:
public class Utils {
public static List<String> enumAsListString(Enum e) {
return e.values().stream.map(e::getMessage).collect(Collectors.toList());
}
}
这可能是您需要在 DRY 和使用枚举之间做出选择的情况之一。
就代码重用而言,枚举并没有走得太远,至少在 Java 中是这样;这样做的主要原因是使用枚举的主要好处是在静态代码中获得——我的意思是 static 作为“非动态”/“运行时”,而不是 static
:).尽管您可以“减少”代码重复,但如果不引入依赖性(是的,这适用于添加通用 API/interface,将 asListString
的实现提取到实用程序 class).这仍然是一个不受欢迎的权衡。
此外,如果您必须使用枚举(出于对序列化、数据库映射、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);
}
}
这是非常可扩展的,尽管它引入了验证数据的需要,其中枚举将静态地防止错误的选项,并且可能需要自定义代码,其中枚举将提供内置支持。
它可以通过“类别”枚举进行改进,它提供对菜单列表的静态访问,以及 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());
}
}
应该清楚的是,您可以用一堆实现通用接口的枚举替换 class MenuOption
,这在 MenuCategory
中应该几乎没有变化。我不会那样做,但这是一个选择。
你可以稍微晾干一下。
Utils.java
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public interface Utils<T>
{
public String getMessage();
public static <T extends Utils<T>> List<String> asListString(Class<T> clazz)
{
return Arrays.stream(clazz.getEnumConstants())
.map(T::getMessage)
.collect(Collectors.toList());
}
}
HostSelectionMethodOptions.java
public enum HostSelectionMethodOptions implements Utils<HostSelectionMethodOptions> {
FIND_ALL("Find all"),
FIND_BY_LASTNAME_PREFIX("Find by last name prefix"),
FIND_BY_CITY_STATE("Find by city & state");
private final String message;
HostSelectionMethodOptions(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
然后就这样做 - Utils.asListString(HostSelectionMethodOptions.class);
我和davidalayachew的想法基本一样
一个枚举可以实现一个接口。因此,如果您创建一个接受 enum
类型的通用 asListString
,您可以获得所需的结果。
首先,创建一个 Options
接口并让两个 enum
实现它:
interface Options {
String getMessage();
}
enum HostSelectionMethodOptions implements Options { ... }
enum MainMenuOptions implements Options { ... }
现在创建一个这样的方法:
public static <T extends Enum<T> & Options> List<String> asListString(Class<T> type) {
return Arrays.stream(type.getEnumConstants())
.map(T::getMessage)
.collect(Collectors.toList());
}
该方法声明了一个类型参数:<T extends Enum<T> & Options>
。这里,T
是一个 交集类型 ,因此它扩展了 Enum
和 Options
接口。你可以这样称呼它:
asListString(MainMenuOptions.class);