Шаблон составной стратегии - Java - Насколько плох этот код? - PullRequest
8 голосов
/ 04 июня 2009

Этот вопрос является продолжением моего предыдущего поста: Реализация шаблона посетителя в java - Как это выглядит?

Я немного запутался при рефакторинге своего кода. Я пытаюсь преобразовать свой шаблон посетителя (объясненный в предыдущем посте) в шаблон составной стратегии. Я пытаюсь сделать что-то вроде этого:

public interface Rule {
  public List<ValidatonError> check(Validatable validatable);
}

Теперь я бы определил правило следующим образом:

public class ValidCountryRule  {
  public List<ValidationError> check(Validatable validatable) {
    // invokeDAO and do something, if violation met
    // add to a list of ValidationErrors.
    // return the list.
  }
}

Теперь я могу проверить объекты двух разных типов. Эти два могут быть совершенно разными: скажем, у меня есть Магазин, который Validatable, а затем Schedule, который Validatable. Теперь, если бы я написал композицию, которая бы выглядела так:

class Validator implements Rule {
  private List<Rule> tests = new ArrayList<Rule>();

  public void addRule(Rule rule) {
    tests.add(rule);
  }

  public List<ValidationError> check(Visitable visitable) {
    List<ValidationError> list = new ArrayList<ValidationError>();
    for(Rule rule : tests) {
      list.addAll(rule.check(visitable);
    }
  }

  public Validator(ValidatorType type) {
    this.tests = type.getRules();
  }
}

Я бы определил enum, который определяет, какой набор проверок куда ...

public Enum ValidatorType {
  public abstract List<Rule> getRules();
  STORE_VALIDATOR {
    public List<Rule> getRules() {
      List<Rule> rules = new ArrayList<Rule>();
      rules.add(new ValidCountryRule());
      rules.add(new ValidXYZRule());
    }

  // more validators
}

и, наконец, я бы использовал это так:

Validator validator = new Validator(ValidatorType.STORE_VALIDATOR);
for (Store store : stores) {
  validator.check(store);
}

У меня странное ощущение, что мой дизайн несовершенен. Мне не нравится идея, что мой интерфейс правил ожидает Validatable. Не могли бы вы подсказать, как мне это улучшить?

Ценю вашу помощь.

Ответы [ 2 ]

9 голосов
/ 04 июня 2009

Когда я впервые узнал о шаблонах проектирования, я продолжал пытаться найти места для их использования. С тех пор я узнал, что преждевременная «паттернизация» является своего рода преждевременной оптимизацией. Сначала попробуйте сделать это прямым способом, а затем посмотрите, какие проблемы это создает.

Попробуйте проектировать с минимальными интерфейсами и подклассами. Затем примените любой шаблон, который подходит для очевидных избыточностей, которые вы обнаружите. Из этого и предыдущего поста у меня сложилось впечатление, что вы, возможно, чрезмерно проектируете свой код.

4 голосов
/ 07 июня 2009

Замените Validatable параметром универсального типа T, чтобы сделать тип структуры проверки достоверности.

public interface Rule<T> {
    public List<ValidationError> check(T value);
}

Давайте расширим нашу платформу с помощью интерфейса ValidationStrategy:

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

Мы имеем дело с правилами, ограниченными "? Super T", поэтому мы можем добавить правило для Animal в Dog Validator (при условии, что Dog расширяет Animal). Валидатор теперь выглядит так:

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 void addRule(Rule<? super T> rule) {
        tests.add(rule);
    }

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

Теперь мы можем реализовать пример DogValidationStrategy следующим образом:

public class DogValidationStrategy implements ValidationStrategy<Dog> {
    public List<Rule<? super Dog>> getRules() {
        List<Rule<? super Dog>> rules = new ArrayList<Rule<? super Dog>>();
        rules.add(new Rule<Dog>() {
            public List<ValidationError> check(Dog dog) {
                // dog check...
                return Collections.emptyList();
            }
        });
        rules.add(new Rule<Animal>() {
            public List<ValidationError> check(Animal animal) {
                // animal check...
                return Collections.emptyList();
            }
        });
        return rules;
    }
}

Или, как в вашем примере, у нас может быть Enum, обеспечивающий несколько стратегий проверки собак:

public enum DogValidationType implements ValidationStrategy<Dog> {
    STRATEGY_1 {
        public List<Rule<? super Dog>> getRules() {
            // answer rules...
        }
    },
    // more dog validation strategies
}
...