2010-11-25 114 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