我想进行重构,并希望创建一个通用类来避免重复代码。我们的项目中有很多XXXCriteriaValidator,我们想要创建一个唯一的类来替换它们。
问题是这个类要求Enum中的静态方法的一行。在这里你会看到。这或多或少是我正在努力实现的目标:
public class GenericCriteriaValidator<T extends ¿SomeKindOfEnumInterface?>
implements CriterionVisitor {
protected Errors errors;
public Errors getErrors() {
return this.errors;
}
/*
* Some code around here
*/
protected void doVisit(final PropertyCriterion criterion) {
if (criterion == null) {
this.errors.reject("error.criterion.null");
} else {
if (criterion.getOperator() == null) {
this.errors.reject("error.operator.null");
}
// Validates property (exception thrown if not exists)
T.fromString(criterion.getName()); // The problem is this call here!!
// Not saying this compiles, just looking
// how to do something equivalent
}
}
}
T总是不同的Enum。典型的枚举是这样的:
public enum ContactCriteria implements CriteriaInterface<ContactCriteria> {
// ^ This interface is added by me
// for the enum being called in the previous class
CONTACT_ID("this.id"),
CONTACT_COMPANY_ID("this.companyId"),
CONTACT_NAME("this.name"),
CONTACT_EMAIL("this.email"),
CONTACT_PHONE_NUMBER("this.phoneNumber"),
CONTACT_ORDER("this.order"),
private final String alias;
ContactCriteria(final String alias) {
this.alias = alias;
}
public String getAlias() {
return this.alias;
}
public static ContactCriteria fromString(final String name) {
ContactCriteria result = null;
if (name != null) {
result = Enum.valueOf(ContactCriteria.class, name);
}
return result;
}
public ContactCriteria returnThis() {
return this;
}
}
最后,我正在寻找第一个类的接口来接受T的fromString方法。我想它应该类似于:
public interface CriteriaInterface<T> {
static T fromString(String name);
// ^ This static is important
}
我没有找到任何与Enum类似的帖子或策略。我知道Enum可以实现一个接口,但不知道如何获得它。
请帮忙。提前致谢
答案 0 :(得分:1)
您应该首先在Java接口中不允许使用静态方法。
接口背后的概念强烈反对静态元素,因为它们属于类而不是对象。
因此,如果枚举中的静态方法只是一个分配给它的容器,但不应该通过任何其他关系连接它。
这里有什么不好的设计,你试着用enum来表达你不应该那么专注的东西,为什么你这么挣扎。
问题是如果enum instance
是CriteriaInterface
,那么为什么要按名称自行提供呢interface Messanger {
String getMessage();
}
。
Enum包含可以表示接口但不能是通用的“常量”的定义。这就是为什么枚举可以实现接口。
表示您可以定义界面
enum Messages {
INFO
WARNING;
}
尝试将其应用于枚举
enum Messages implements Messanger {
INFO,
WARNING;
private String message;
@Override
public String getMessage() {
return message;
}
}
您有两种选择,
首先,创建一个
的字段 enum Messages implements Messanger {
INFO("Info"), //We create an instance of class as we call the constructor
WARNING("Warnig") //We create an instance of class as we call the constructor
;
private final String message;
public Message(String message) {
this.messsage = message;
}
@Override
public String getMessage() {
return message;
}
}
然后你必须添加构造函数来设置字段
enum
当我们在{{1}}的正文中声明实例时,您必须提供创建它所需的所有信息。假设enum允许泛型,那么就是你应该声明它的地方。
答案 1 :(得分:0)
如果您的CriteriaInterface
上有静态方法,则不应该
CriteriaIntervace.fromString("")
因为静态方法属于一个类(在这种情况下是CriteriaIntervace
)而不是一个对象?
答案 2 :(得分:0)
你不能在界面中放置静态方法,泛型等对此没有直接影响。接口定义了对象实例的方法,静态方法不是实例接口的一部分,它们是类接口的一部分。
最简单的解决方法是向GenericCriteriaValidator提供工厂对象,或者将其设为抽象并提供:
abstract T getEnum(String name);
然后,每个实现都可以为它正在使用的枚举实现getEnum。
答案 3 :(得分:0)
嗯,一般来说,泛型类型已被删除,除了明确告诉GenericCriteriaValidator
应该应用哪种验证逻辑之外,你没有其他机会。您可能希望抽象某种类型的接收并使用工厂模式,这样就可以为fromString
方法定义接口。
这会导致类似这样的事情:
public interface CriteriaInterface<T> {
static class Factory<U> {
U fromString(String name);
}
}
但是,我在你的例子中并没有看到这样做的好处。只需要CriteriaInterface<T>
的实例作为GenericCriteriaValidator
的构造函数参数,并在此界面中定义某种validate
方法。
但是,如果你真的想要避免这种情况,那就有一个解决方案。可以读取其他类的超类的泛型类型(这是相当hacky,需要反射,我不推荐它,但有些库喜欢这种方法)。这要求您在使用泛型类时始终声明一个匿名子类:
class GenericCriteriaValidator<T extends Enum<?>> implements CriterionVisitor {
private final Method criteria;
public GenericCriteriaValidator() {
ParameterizedType parameterizedType = (ParameterizedType) getClass()
.getGenericSuperclass();
try {
criteria = ((Class<?>) parameterizedType.getActualTypeArguments()[0])
.getMethod("fromString", String.class);
criteria.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException(e);
}
}
@SuppressWarning("unchecked")
private CriteriaInterface<?> invokeFromString(String value) {
try {
return (CriteriaInterface<?>) criteria.invoke(null, value);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
}
}
// Your other code goes here.
}
请注意,您需要将GenericCriteriaValidator
实例化为匿名子类:
new GenericCriteriaValidator<ContactCriteria>() { }; // mind the braces!
正如我所说。我不觉得这很直观,而且肯定不是“Java方式”,但你可能仍然想要考虑它。