设计问题-java-实现这一点的最佳方法是什么?
我有一个设计问题 我有两个数据对象,它们是类A和类B的实例。 A和B没有任何行为——它们是带有getter和setter的Javabean。 我有一个验证接口和10个定义不同验证的实现。 我想在我的属性文件中指定哪个验证应用于哪个类。 大概是这样的:设计问题-java-实现这一点的最佳方法是什么?,java,oop,Java,Oop,我有一个设计问题 我有两个数据对象,它们是类A和类B的实例。 A和B没有任何行为——它们是带有getter和setter的Javabean。 我有一个验证接口和10个定义不同验证的实现。 我想在我的属性文件中指定哪个验证应用于哪个类。 大概是这样的: A类XYZ验证,ABC验证 B类:ABC验证、PPV验证等 我如何编写我的验证类,以便它服务于类A或类B的实例,或者我将来可能要添加的任何其他类C的实例 interface Validation { public boolean check(?
A类XYZ验证,ABC验证 B类:ABC验证、PPV验证等
我如何编写我的验证类,以便它服务于类A或类B的实例,或者我将来可能要添加的任何其他类C的实例
interface Validation {
public boolean check(??);
}
>我只想加上这句话,向所有回复这篇文章的人表示感谢,并说我很喜欢在这个令人惊叹的网站上度过的时光。堆积如山的岩石您是否考虑过使用注释来标记要在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);
}
}
}
}
用于注释界面
EDIT2:请不要直接修改字段(如上面的示例所示)。相反,使用反射访问他们的getter和setter。我可能误解了这个问题,但这样就足够了:
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);
}
}
公共类验证映射{
私有映射=新的HashMap();
公共验证映射(){
put(A.class,新类[]{XYZValidation.class,ABCValidation.class});
put(B.class,新类[]{ABCValidation.class,PPPValidation.class});
}
公共类[]getValidators(类cls){
if(!mappings.containsKey(cls))返回新类[]{};
返回mappings.get(cls);
}
}
当您想要获取特定类的验证器列表时,您可以调用getValidators(类cls)并迭代每个验证器,为每个验证器创建一个实例,然后调用您的检查方法。可能是这样的吗
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;
}
}
若你们只想让它处理任何对象,那个么它就是你们的接口
interface Validator {
boolean isValid(Object object);
}
公共布尔检查(对象o)
除非您想使用一些标记接口来标记适合验证的类,否则您的意思是:
public interface Validation<T> {
boolean check(T object)
}
公共接口验证{
布尔检查(T对象)
}
首先,我将使用以下界面
interface Validator {
boolean isValid(Object object);
}
隐式记录返回值的实际含义
第二,我建议在接口中记录如果验证器不知道如何处理给定实例,预期的行为
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);
}
这样,您就可以简单地拥有一个验证器列表,您可以向其抛出对象
如果不兼容验证器的实现正确(例如,使用早期instanceof),那么它们对性能的影响应该可以忽略不计
另一方面,我会使用一个验证器列表而不是一个集合,这样您就可以根据复杂性对它们进行排序。将便宜的(性能方面的)验证器作为优化放在列表的开头
然后可以使用一段通用代码进行验证,例如
public class Validators {
public static boolean isValid(Object o, Collection<Validator> validators) {
for(Validator current : validators) {
if(!current.isValid()) return false;
}
return true;
}
}
公共类验证程序{
公共静态布尔值isValid(对象o、集合验证器){
for(当前验证程序:验证程序){
如果(!current.isValid())返回false;
}
返回true;
}
}
根据您的用例,最好在接口中返回与布尔值不同的值。如果您需要有关什么是错误的信息,例如要显示它,您需要返回该信息
在这种情况下,保持上述循环运行可能是一个好主意,这样您将获得所有验证错误,而不仅仅是第一个错误。访问者模式将解决此问题 调用Visitor Validator可以实现以下功能: 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); } } 可验证的公共接口{ 公共布尔验证(验证器v); } 公共接口验证程序{ 公共布尔验证(A); 公共布尔验证(B); } 公共类A实现了可验证的{ 公共布尔验证(验证器v){ 返回v.validate(这个); } } 公共类B实现了可验证的{ 公共无效验证(验证程序v){ 返回v.validate(这个); } } //默认验证器只是不知道如何 //既不验证A,也不验证B 公共类GenericValidator实现验证器{ 公共布尔验证(A){ 抛出新的UnsupportedOperationException(“无法验证A”); } 公共布尔验证(B){ 抛出新的UnsupportedOperationException(“无法验证B”); } } //因为XYZValidation应该只在A上运行 //它只覆盖验证 公共类XYZValidation扩展了GenericValidator{ 公共布尔验证(A){ //验证 返回有效(a); } } //因为ABC验证应该在A和B上运行 //它覆盖了A和B验证 公共类ABCValidation扩展了GenericValidator{ 公共布尔验证(A){ //验证 返回有效(a); } 公共布尔验证(B){ //验证b 返回有效(b); } } //因为ABCValization应该只在B上运行 //它只覆盖A和B验证 公共类PPPValidation扩展了GenericValidator{ 公共布尔验证(B){ //验证b 返回有效(b); } }
我也在考虑这个方向,但我喜欢带注释的解决方案。我不喜欢它,因为在check方法中,必须将Validatable强制转换为具体对象。泛型是一个更好、更安全的选择:类验证器{boolean validate(T object);}好吧,我建议将泛型与我的解决方案结合起来:可验证接口是一个人工约束,它不会给你带来任何好处。我错过了一些吗