设计问题 - java - 这样做的最佳方法是什么?

时间:2009-06-05 07:36:04

标签: java oop

我遇到了设计问题。

我有两个数据对象,分别是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晃动!

7 个答案:

答案 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);
  }
}