如何在不覆盖方法的情况下在枚举中实现接口(带参数)
How to implement Interface in Enums (with parameters) without overriding methods
我有如下 Enumutils:
public interface EnumUtil {
String getValue();
static <T extends Enum<T> & EnumUtil> T fromValue(String enumValue, Class<T> type) {
EnumSet<T> all=EnumSet.allOf(type);
for (final T t: all) {
System.out.println("Value: " + t.getValue());
System.out.println("Name: " + t.name());
T val = T.valueOf(t.getDeclaringClass(), t.name()).;
System.out.println("ValValVal: " + val);
if (t.getValue().equalsIgnoreCase(enumValue)) {
return t;
}
}
return null;
}
}
然后我创建了一个枚举,如下所示:
@Getter
@AllArgsConstructor
public enum SupportedOptions implements EnumUtil {
PART("PART"),
MSRV("MSRV");
private final String value; //If we add this line then we need not to override getValue()
public static SupportedOptions fromValue(final String text) {
return EnumUtil.fromValue(text, SupportedOptions.class);
}
}
这工作正常,没有任何编译问题。 (getValue 也returns 枚举参数在 EnumUtils 接口的 fromvalue 中成功用于此枚举)
但在下面的场景中会导致编译时异常(需要实现抽象方法)
@Getter
@AllArgsConstructor
public enum RejectedResponseCode implements EnumUtil {
UNPR("300", "849", "700", "701", "702", "703", "705", "730","704"),
IMSG("302", "105", "113", "114"),
PARS("107", "100", "102", "103", "115","720"),
SECU("302", "668", "669", "670", "671");
//approach 1
private final String value; //Here it want some value as i am using constructor like below
RejectedResponseCode(final String... codes) {
this.codes = Arrays.asList(codes);
//this.value = getValue(); <--- Is this approach fine. (For appraoch 1)
}
private final List<String> codes;
public static RejectedResponseCode getValueOfData(final String value) {
final Optional<RejectedResponseCode> result = Arrays.stream(values()).filter(rejectedResponseCode -> rejectedResponseCode.codes.contains(value)).findFirst();
if (result.isPresent()) {
return result.get();
}
return null;
}
public static RejectedResponseCode fromValue(final String text) {
return EnumUtil.fromValue(text, RejectedResponseCode.class);
}
//Approach 2
//@Override
//public String getValue(){
// return null; //Is this approach correct?
//}
}
如何忽略不覆盖getValue()?
或者如何以 returns 参数的方式覆盖 getValue()
或任何其他方式在 EnumUtil 中管理它?
按照 Joachim Sauer 在评论中的指示:
EnumUtil.fromValue() 简单地假设每个枚举值始终只有一个标识字符串。对于您的第二个样本,情况并非如此。所以要么不要使用 EnumUtil.fromValue() 要么扩展它来支持多个值(可能通过有第二个接口可以 return 数组或潜在标识符的集合)–
因此,EnumUtils 从枚举中删除并仅在枚举内部创建方法。
您需要搜索支持多个搜索键的每个枚举值,因此实现 getValue
是没有用的。解决这个问题的方法是反转操作,使枚举提供一组要使用的搜索条件,并在 EnumUtil 上实现一个简单的实用方法:
public class EnumUtil {
@SafeVarargs
public static <T,V> T match(T[] values, V fieldValue, BiPredicate<T,V> ... checks) {
for (var pred : checks)
for (T item : values)
if(pred.test(item, fieldValue))
return item;
return null; // OR throw new IllegalArgumentException("Not found: "+fieldValue);
}
}
然后您的枚举 类 可以设置任意数量的搜索参数。 SupportedOptions 仅匹配名称:
enum SupportedOptions {
PART,
MSRV;
public static SupportedOptions fromValue(final String text) {
return EnumUtil.match(values(), text.toUpperCase(), (e, s) -> e.name().equals(s));
}
}
RejectedResponseCode 在 name()
和 codes.indexOf
上匹配:
enum RejectedResponseCode {
UNPR("300", "849", "700", "701", "702", "703", "705", "730","704"),
IMSG("302", "105", "113", "114"),
PARS("107", "100", "102", "103", "115","720"),
SECU("302", "668", "669", "670", "671");
RejectedResponseCode(final String... codes) {
this.codes = Arrays.asList(codes);
}
private final List<String> codes;
public static RejectedResponseCode fromValue(final String text) {
return EnumUtil.match(values(), text.toUpperCase(), (e, s) -> e.name().equals(s), (e, s) -> e.codes.indexOf(s) >= 0);
}
}
所以,任何东西都可以通过名称定位:
public static void main(String[] args)
{
for (String s : new String[] { "PART", "msrv", "other"})
System.out.println("SupportedOptions.fromValue("+s+") => "+ SupportedOptions.fromValue(s));
for (String s : new String[] { "UNPR", "imsg", "102", "671", "999999"})
System.out.println("RejectedResponseCode.fromValue("+s+") => "+ RejectedResponseCode.fromValue(s));
}
SupportedOptions.fromValue(PART) => PART
SupportedOptions.fromValue(msrv) => MSRV
SupportedOptions.fromValue(other) => null
RejectedResponseCode.fromValue(UNPR) => UNPR
RejectedResponseCode.fromValue(imsg) => IMSG
RejectedResponseCode.fromValue(102) => PARS
RejectedResponseCode.fromValue(671) => SECU
RejectedResponseCode.fromValue(999999) => null
我有如下 Enumutils:
public interface EnumUtil {
String getValue();
static <T extends Enum<T> & EnumUtil> T fromValue(String enumValue, Class<T> type) {
EnumSet<T> all=EnumSet.allOf(type);
for (final T t: all) {
System.out.println("Value: " + t.getValue());
System.out.println("Name: " + t.name());
T val = T.valueOf(t.getDeclaringClass(), t.name()).;
System.out.println("ValValVal: " + val);
if (t.getValue().equalsIgnoreCase(enumValue)) {
return t;
}
}
return null;
}
}
然后我创建了一个枚举,如下所示:
@Getter
@AllArgsConstructor
public enum SupportedOptions implements EnumUtil {
PART("PART"),
MSRV("MSRV");
private final String value; //If we add this line then we need not to override getValue()
public static SupportedOptions fromValue(final String text) {
return EnumUtil.fromValue(text, SupportedOptions.class);
}
}
这工作正常,没有任何编译问题。 (getValue 也returns 枚举参数在 EnumUtils 接口的 fromvalue 中成功用于此枚举)
但在下面的场景中会导致编译时异常(需要实现抽象方法)
@Getter
@AllArgsConstructor
public enum RejectedResponseCode implements EnumUtil {
UNPR("300", "849", "700", "701", "702", "703", "705", "730","704"),
IMSG("302", "105", "113", "114"),
PARS("107", "100", "102", "103", "115","720"),
SECU("302", "668", "669", "670", "671");
//approach 1
private final String value; //Here it want some value as i am using constructor like below
RejectedResponseCode(final String... codes) {
this.codes = Arrays.asList(codes);
//this.value = getValue(); <--- Is this approach fine. (For appraoch 1)
}
private final List<String> codes;
public static RejectedResponseCode getValueOfData(final String value) {
final Optional<RejectedResponseCode> result = Arrays.stream(values()).filter(rejectedResponseCode -> rejectedResponseCode.codes.contains(value)).findFirst();
if (result.isPresent()) {
return result.get();
}
return null;
}
public static RejectedResponseCode fromValue(final String text) {
return EnumUtil.fromValue(text, RejectedResponseCode.class);
}
//Approach 2
//@Override
//public String getValue(){
// return null; //Is this approach correct?
//}
}
如何忽略不覆盖getValue()? 或者如何以 returns 参数的方式覆盖 getValue() 或任何其他方式在 EnumUtil 中管理它?
按照 Joachim Sauer 在评论中的指示:
EnumUtil.fromValue() 简单地假设每个枚举值始终只有一个标识字符串。对于您的第二个样本,情况并非如此。所以要么不要使用 EnumUtil.fromValue() 要么扩展它来支持多个值(可能通过有第二个接口可以 return 数组或潜在标识符的集合)–
因此,EnumUtils 从枚举中删除并仅在枚举内部创建方法。
您需要搜索支持多个搜索键的每个枚举值,因此实现 getValue
是没有用的。解决这个问题的方法是反转操作,使枚举提供一组要使用的搜索条件,并在 EnumUtil 上实现一个简单的实用方法:
public class EnumUtil {
@SafeVarargs
public static <T,V> T match(T[] values, V fieldValue, BiPredicate<T,V> ... checks) {
for (var pred : checks)
for (T item : values)
if(pred.test(item, fieldValue))
return item;
return null; // OR throw new IllegalArgumentException("Not found: "+fieldValue);
}
}
然后您的枚举 类 可以设置任意数量的搜索参数。 SupportedOptions 仅匹配名称:
enum SupportedOptions {
PART,
MSRV;
public static SupportedOptions fromValue(final String text) {
return EnumUtil.match(values(), text.toUpperCase(), (e, s) -> e.name().equals(s));
}
}
RejectedResponseCode 在 name()
和 codes.indexOf
上匹配:
enum RejectedResponseCode {
UNPR("300", "849", "700", "701", "702", "703", "705", "730","704"),
IMSG("302", "105", "113", "114"),
PARS("107", "100", "102", "103", "115","720"),
SECU("302", "668", "669", "670", "671");
RejectedResponseCode(final String... codes) {
this.codes = Arrays.asList(codes);
}
private final List<String> codes;
public static RejectedResponseCode fromValue(final String text) {
return EnumUtil.match(values(), text.toUpperCase(), (e, s) -> e.name().equals(s), (e, s) -> e.codes.indexOf(s) >= 0);
}
}
所以,任何东西都可以通过名称定位:
public static void main(String[] args)
{
for (String s : new String[] { "PART", "msrv", "other"})
System.out.println("SupportedOptions.fromValue("+s+") => "+ SupportedOptions.fromValue(s));
for (String s : new String[] { "UNPR", "imsg", "102", "671", "999999"})
System.out.println("RejectedResponseCode.fromValue("+s+") => "+ RejectedResponseCode.fromValue(s));
}
SupportedOptions.fromValue(PART) => PART
SupportedOptions.fromValue(msrv) => MSRV
SupportedOptions.fromValue(other) => null
RejectedResponseCode.fromValue(UNPR) => UNPR
RejectedResponseCode.fromValue(imsg) => IMSG
RejectedResponseCode.fromValue(102) => PARS
RejectedResponseCode.fromValue(671) => SECU
RejectedResponseCode.fromValue(999999) => null