Как уже говорили другие, класс слишком велик, когда он пытается сделать больше чем одно, и нарушает принцип единой ответственности .
Отличная книга на эту и другие темы (и я настоятельно рекомендую ее для любого разработчика) - Чистый код Боба Мартина.
Замените 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 to Dog (при условии, что 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
}
Когда я впервые узнал о шаблонах проектирования, я все время пытался найти места для их использования. С тех пор я узнал, что преждевременная «паттернизация» похожа на преждевременную оптимизацию. Сначала попытайтесь сделать это прямым способом, а затем посмотрите, какие проблемы это дает вам.
Попробуйте разработать с минимальными интерфейсами и подклассами. Затем примените любой шаблон, который может подойти для обнаруженных вами очевидных избыточностей. Из этого и предыдущего поста у меня сложилось впечатление, что вы можете перестроить свой код.