我遇到了设计问题。
我有两个数据对象,分别是A类和B类的实例。
A和B没有任何行为 - 它们是带有getter和setter的java bean。
我有一个验证界面和10个实现它定义不同的验证。
我想在我的属性文件中指定哪个Validation适用于哪个类。
像这样的东西:
A类XYZValidation,ABCValidation
B类:ABCValidation,PPPValidation等
如何编写我的Validation类,以便它提供作为Class A OR ClassB实例的对象,或者我将来可能要添加的任何其他C类?
interface Validation {
public boolean check(??);
}
>只是想添加这一行,感谢所有回复此帖的人,并说我喜欢这个神奇网站上的时间。 Stackoverflow晃动!
答案 0 :(得分:8)
您是否考虑过使用注释来标记要在bean中验证的字段?
如果您有10种不同的验证,则可以指定10个注释。然后使用注释标记字段:
@ValideStringIsCapitalCase
private String myString;
@ValidateIsNegative
private int myInt;
使用反射API遍历所有字段并查看它们是否已标记,如下所示:
public static <T> validateBean(T myBean) throws IllegalAccessException {
Field[] fields = myBean.getClass().getDeclaredFields();
// This does not take fields of superclass into account
if (fields != null) {
for (Field field : allFields) {
if (field.isAnnotationPresent(ValideStringIsCapitalCase.class)) {
field.setAccessible(true);
Object value = field.get(existingEntity);
// Validate
field.setAccessible(false);
}
}
}
}
选项是使用您要使用的验证器标记整个类。
编辑:记得包含注释:
@Retention(RetentionPolicy.RUNTIME)
用于注释界面。
EDIT2:请不要直接修改字段(如上例所示)。而是使用反射访问他们的getter和setter。
答案 1 :(得分:3)
我可能误解了这个问题,但这样就足够了:
public class ValidationMappings {
private Map<Class, Class<Validation>[]> mappings = new HashMap<Class, Class<Validation>[]>();
public ValidationMappings() {
mappings.put(A.class, new Class[]{XYZValidation.class, ABCValidation.class});
mappings.put(B.class, new Class[]{ABCValidation.class, PPPValidation.class});
}
public Class[] getValidators(Class cls) {
if (!mappings.containsKey(cls)) return new Class[]{};
return mappings.get(cls);
}
}
当您想获取特定类的验证器列表时,您将调用getValidators(Class cls)并遍历每个验证器并创建每个验证器的实例并调用您的检查方法。
答案 2 :(得分:3)
这样的事可能吗?
interface Validation {
public boolean check(Validatable x);
}
interface Validatable {
}
class A implements Validatable {
...
}
class Validator {
public boolean validateObject(Validatable x){
boolean validated = true;
... //read config file, check which validation classes to call
//for each validation class v in the config file:
if(!v.check(x)) validated = false;
return validated;
}
}
答案 3 :(得分:2)
如果你只是想让它处理任何对象,那么它就是你的界面
的对象public boolean check(Object o);
除非您想使用某些标记接口来标记适合验证的类
答案 4 :(得分:2)
你的意思是:
public interface Validation<T> {
boolean check(T object)
}
答案 5 :(得分:0)
首先,我使用以下界面
interface Validator {
boolean isValid(Object object);
}
隐式记录返回值的实际含义。
其次,如果Validator不知道如何处理给定的实例,我建议在接口中记录预期的行为。
interface Validator {
/**
* @return false if this validator detects that the given instance is invalid, true if the given object is valid or this Validator can't validate it.
*/
boolean isValid(Object object);
}
这样,您只需要一个可以抛出对象的验证器列表。
如果正确实施不兼容的验证器,性能影响可以忽略不计,例如:早期的实例。
另外,我会使用Validator列表而不是Set,这样您就可以根据复杂程度对它们进行排序。将廉价(性能方面)验证器放在List的开头作为优化。
然后,您可以使用一般代码进行验证,例如
public class Validators {
public static boolean isValid(Object o, Collection<Validator> validators) {
for(Validator current : validators) {
if(!current.isValid()) return false;
}
return true;
}
}
根据您的使用情况,在界面中返回不同于布尔值的内容可能是个好主意。如果您需要有关 错误的信息,例如要显示它,您需要返回该信息。
在这种情况下,保持上述循环运行可能是一个好主意,因此您将获得所有验证错误,而不仅仅是第一个。
答案 6 :(得分:0)
访客模式可以解决此问题
调用访客验证器可以实现此目的:
public interface Validatable { public boolean validate(Validator v); } public interface Validator { public boolean validate(A a); public boolean validate(B b); } public class A implements Validatable { public boolean validate(Validator v){ return v.validate(this); } } public class B implements Validatable { public void validate(Validator v) { return v.validate(this); } } // Default validator just doesn't know how to // validate neither A's, nor B's public class GenericValidator implements Validator { public boolean validate(A a) { throw new UnsupportedOperationException("Cannot validate A"); } public boolean validate(B b) { throw new UnsupportedOperationException("Cannot validate B"); } } // since XYZValidation is supposed to run only on A's // it only overrides A validation public class XYZValidation extends GenericValidator { public boolean validate(A a) { // validate a return isVAlid(a); } } // since ABCValidation is supposed to run on A's and B's // it overrides A and B validation public class ABCValidation extends GenericValidator { public boolean validate(A a) { // validate a return isVAlid(a); } public boolean validate(B b) { // validate b return isVAlid(b); } } // since ABCValidation is supposed to run only on B's // it overrides A only B validation public class PPPValidation extends GenericValidator { public boolean validate(B b) { // validate b return isVAlid(b); } }