Типизированные безопасные правила - PullRequest
2 голосов
/ 25 ноября 2010

У меня есть небольшой набор классов проверки, которые я создал, которые хорошо мне помогли, однако теперь мне нужно обновить их для обработки приоритетных правил. Если соблюдается правило с высоким приоритетом, мне не нужно выполнять дальнейшие проверки, поскольку мы просто сообщим пользователю одно сообщение об ошибке вместо добавления всего набора сообщений пользователю.

Вот набор классов, которые у меня есть:

//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 Ответ

2 голосов
/ 25 ноября 2010

Как насчет создания абстрактного базового класса для обработки сравнений правил:

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 должны быть сопоставимы друг с другом, поэтому я рекомендую, чтобы PrioritizedRule была абстрактной базой, а не интерфейсом, потому что именно здесь должна существовать реализация CompareTo для согласованности. Ваш метод CompareTo не обязательно должен соответствовать «Равным», если только вы не попытаетесь сохранить свою коллекцию в отсортированном наборе, который никогда не может хорошо закончиться (PrioritizedRule не может знать достаточно, чтобы привести себя в соответствие с «Равными»!), Поэтому не пытайтесь .

В качестве альтернативы, внедрите Comparator>, но опять же, ваш интерфейс правила должен быть изменен, чтобы предоставить достаточно информации для сортировки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...