Прежде всего, я бы использовал следующий интерфейс
interface Validator {
boolean isValid(Object object);
}
для неявного документирования того, что на самом деле означает возвращаемое значение.
Во-вторых, я бы предложил задокументировать в интерфейсе, какое поведение ожидается, если Валидатор не знает, как обрабатывать данный экземпляр.
interface Validator {
/**
* @return false if this validator detects that the given instance is invalid, true if the given object is valid or this Validator can't validate it.
*/
boolean isValid(Object object);
}
Таким образом, у вас будет просто список валидаторов, в который вы можете бросить свои объекты.
Влияние производительности несовместимых валидаторов должно быть незначительным, если они реализованы должным образом, например, с ранним экземпляром.
Кстати, я бы использовал Список валидаторов вместо набора, чтобы вы могли упорядочить их в соответствии со сложностью. Поместите дешевые (с точки зрения производительности) валидаторы в начало списка в качестве оптимизации.
Затем вы можете использовать общий кусок кода для проверки, например,
public class Validators {
public static boolean isValid(Object o, Collection<Validator> validators) {
for(Validator current : validators) {
if(!current.isValid()) return false;
}
return true;
}
}
В зависимости от вашего варианта использования может быть хорошей идеей вернуть что-то отличное от логического в вашем интерфейсе. Если вам нужна информация о , что не так, например, чтобы отобразить его, вам нужно будет вернуть эту информацию.
В этом случае может быть хорошей идеей сохранить вышеуказанный цикл работающим, чтобы вы получали все ошибки проверки, а не только первые.