Typesafe优先规则

时间:2010-11-25 02:31:07

标签: java validation generics

我有一小组验证类,我已经创建了很好的服务,但是现在我需要更新它们以处理优先级规则。如果满足高优先级规则,那么我不需要再运行任何验证,因为我们只会告诉用户一条错误消息,而不是将整组消息添加到用户。

以下是我所拥有的课程集:

//Rule.java
public interface Rule<T> {
    List<ErrorMessage> validate(T value);
}

//ValidationStrategy.java
public interface ValidationStrategy<T> {
    public List<Rule<? super T>> getRules();
}

//Validator.java
public class Validator<T> implements Rule<T> {

    private List<Rule<? super T>> tests = new ArrayList<Rule<? super T>>();

    public Validator(ValidationStrategy<T> type) {
        this.tests = type.getRules();
    }

    public List<ErrorMessage> validate(T value) {
        List <ErrorMessage> errors = new ArrayList<ErrorMessage>();
            for (Rule<? super T> rule : tests) {
                errors.addAll(rule.check(value));
            }
            return errors;
    }
}

我在修改此代码以处理优先级规则时遇到一些问题。当然有一些东西我可以修改使用而不是引入规则引擎。

理想情况下,我可以创建这样的规则:

private static final Rule<SomeClass> ensureAllFieldsNotBlank = new Rule<SomeClass>(RulePriority.HIGHEST) {

    public List<ErrorMessage> check(SomeClass someClass) {
        List<ErrorMessage> errors = new ArrayList<ErrorMessage>();
        if (StringUtils.isBlank(someClass.getValue1())
            && StringUtils.isBlank(someClass.getValue2())
            && StringUtils.isBlank(someClass.getValue3())) {
                errors.add("Provide a response for \"" + someClass.getName() + "\"");
        }
        return errors;
    }
};

编辑更新的课程:

//ValidationStrategy.java
public interface ValidationStrategy<T> {
    public List<Rule<? super T>> getRules(RulePriority rulePriority);
}

//RulePriority.java
public enum RulePriority { HIGHEST, DEFAULT, LOWEST; }

//Validator.java
public class Validator<T> implements Rule<T> {
   private List<Rule<? super T>> tests = new ArrayList<Rule<? super T>>();
   private ValidationStrategy<T> validationStrategy;

   public Validator(ValidationStrategy<T> validationStrategy) {
       this.validationStrategy = validationStrategy;
       for (RulePriority rp : RulePriority.values()) {
           this.tests.addAll(validationStrategy.getRules(rulePriority));
       }
   }

   public List<ErrorMessage> validate(T value) {
       List<ErrorMessage> errors = new ArrayList<String>();
       for (RulePriority rp : RulePriority.values()) {
           for (Rule<? super T> rule : validationStrategy.getRules(rp)) {
               errors.addAll(rule.validate(value));
           }
           if (errors.size() > 0) {
               break;
           }
       }
       return errors;
   }

1 个答案:

答案 0 :(得分:2)

如何创建一个抽象基类来处理规则比较:

abstract class PrioritizedRule<T> implements Rule<T>, Comparable<PrioritizedRule<T>>{
    public int compareTo(PrioritizedRule<T> other){
        //Implement something that compares rule priorities here.
        //This will probably require support from the constructor, which-
        //since this is abstract- must be Protected.

从那里开始,您的PrioritizedValidator(需要PrioritizedRule)将在Validate的开头对它的集合进行排序()(如果自上次验证后其规则集已被修改;这是对集合进行排序的正确时间,因为我们没有如果有连续的修改,我们想要在每次修改时重复排序,或者如果我们不需要,则进行排序),如果错误消息列表在转换过程中非空,则Validate循环应提前输出规则优先级之间:

public List<ErrorMessage> validate(T value) {
    if(ruleSetModified){
        //be careful: validate becomes unsafe for multithreading here, even if you
        //aren't modifying the ruleset; if this is a problem, implement locking
        //inside here. Multiple threads may try to sort the collection, but not
        //simultaneously. Usually, the set won't be modified, so locking before
        //the test is much, much slower. Synchronizing the method is safest,
        //but carries a tremendous performance penalty
        Collections.sort(rule);
        ruleSetModified = false;
    }
    List <ErrorMessage> errors = new ArrayList<String>();
        PrioritizedRule prev = null;
        for (PrioritizedRule<? super T> rule : tests) {
            if(prev != null && prev.compareTo(rule) != 0 && !errors.isEmpty()){
                return errors;
            }
            errors.addAll(rule.check(value));
            prev = rule;
        }
        return errors;
}

我不确定你的意思是“......没有引入规则引擎”,但定义规则来排序自己可能是最优雅的方法。但是要小心 - 任何两个PrioritizedRule-s必须相互比较,这就是为什么我建议将PrioritizedRule作为抽象基础而不是接口,因为这是compareTo实现需要生存的地方,以保持一致性。你的compareTo不需要与equals保持一致,除非你试图将你的集合保存在一个排序集中,这个集合永远不能很好地结束(PrioritizedRule不能足够意识到它与equals一致!),所以不要尝试

或者,实现Comparator&gt;,但同样需要修改您的Rule接口以显示足够的信息以进行排序。