2010-11-25 76 views
2

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

下面是一组类,我有:

//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; 
    } 

回答

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)将sort()它的coll在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>,但同样需要修改Rule接口以公开足够的信息进行排序。

+0

我喜欢这种方法,但我只想指出,很容易让`compareTo()`与`equals()`一致 - 只需调用它即可!如果他们相等返回0,否则返回任何东西,但。 – CurtainDog 2010-11-25 03:32:56