假设我有一堆逻辑上不同的java枚举,它们不能合并在一起,因为某些先前的操作依赖于每个独立的枚举。
enum Enum1 {
ENUM1VAL1,
ENUM1VAL2
}
enum Enum2 {
ENUM2VAL1,
ENUM2VAL2
}
void existingOperationOnEnum1(Enum1 enum1);
void existingOperationOnEnum2(Enum2 enum2);
现在,假设我想定义一个新的操作来检查一个字符串是否可以转换为这些枚举中的任何一个
void isValidStringConversionForEnums(final String input) {
ENUM1.valueOf(input); // Throws IllegalArgumentException if conversion not possible
ENUM2.valueOf(input); // Throws IllegalArgumentException if conversion not possible
}
这很好,但它不能扩展。业务逻辑是这样的,我们可以在将来创建新的枚举(使用它自己的一组特定于枚举的操作),但是每次添加新枚举时都需要更新isValidStringConversionForEnums,程序员可能很容易忘记这一点。
所以我的问题是我如何修改isValidStringConversionForEnums,使其与未来的扩展工作。
我想的一种方法是创建一个接口EnumBase,让枚举扩展它,然后使用反射来获得所有Enum impls,但我不希望在运行时使用反射,除非我必须。
是否有另一种方法可以这样写,我添加一个新的enum和isValidStringConversionForEnums以某种方式处理这个新enum。
你有两个独立的问题:
- 给定一个枚举类型列表,如何编写代码来测试您的字符串至少可转换为其中之一?
- 您如何获得该列表?
这两个问题完全不相关。所以,你分别解决它们。
给定一个列表…
Class<? extends Enum>
可能是你最好的选择。
enum Test1 {
FOO, BAR;
}
enum Test2 {
FOO, BAZ;
}
public static void isValidStringConversionForEnums(String in, Class<? extends Enum>... enumTypes) {
for (var enumType : enumTypes) {
for (var c : enumType.getEnumConstants()) {
if (c.name().equals(in)) return true;
}
}
return false;
}
这不是特别有效-但您得到了要点。你可以预先创建一个包含所有有效值的HashSet,然后它只是一个.containsKey()
调用,使用上面的代码来代替一次性的"初始化"。比如创建HashSet。如果您确实需要枚举常量,则使用Map<String, List<? extends Enum<?>>
代替。computeIfAbsent
是在一行代码中动态创建这些列表的好方法。
java类加载器抽象系统根本没有"给我一个jar中所有文件的列表"或"给我一个所有类的列表"。有些库似乎提供了这些功能,但它们并不总是有效,所以你可能不想使用它们。
这个问题的标准解决方案,由JVM本身也使用,是'SPI' -与module-info.java它的烘烤,如果你不使用它(你可能不应该,它有点棘手,那),有ServiceLoader
。要制作服务文件,你可以使用注释处理器,我认为周围有一些可以自动化它。
然后流程很简单,要创建一个新的枚举,在其上粘贴一个@ProviderFor(Something.class)
,其中Something.class
是您设计的一些标记接口。
请注意,如果要扫描所有在整个类路径上添加枚举简直太糟糕了。java内部使用了各种各样的枚举,如果其中一个恰好有一个值等于你的字符串呢?这不会突然使它成为一个有效的字符串。不,只有你明确标记为适用于这个问题的枚举,限定,这个,你需要做一些来标记它们。要么使用注释,要么显式地写出完整的列表。