Проверка входных данных удивительно сложна, и все три из предложенных подходов в исходном посте необходимы, а иногда и больше.Исключения уместны, когда ввод находится за пределами бизнес-логики, если он поврежден или не может быть прочитан, например.
Проверка флагов быстро становится анти-шаблоном, если у вас есть более одного или двух флагов для проверки,и может быть заменен слегка специализированной версией шаблона посетителя.Я не знаю точного названия этого конкретного шаблона, но я неофициально назову его « шаблон списка валидатора » и опишу его более подробно ниже.
Проверка ввода на ранней стадии инеудача быстро обычно хороша, но не всегда возможна.Часто существует лот проверки входных данных, все входные данные, полученные извне вашего элемента управления, должны рассматриваться как враждебные и требуют проверки.Хороший дизайн и архитектура программы помогут понять, когда именно это должно произойти.
'Шаблон списка валидаторов'
В качестве примера давайте сначала опишем в кодеанти-шаблон «Флаг проверки», а затем мы преобразуем его в шаблон «Список проверки».
public Optional<String> checkForErrorsUsingFlags(
ObjectToCheck objToCheck ) {
// the small series of checks and if statements represent the
// anti-pattern. Hard to test and many other problems crop up.
String errMsg = checkForError1( objToCheck );
if(errMsg != null ) {
return Optional.of(errMsg);
}
errMsg = checkForError2( objToCheck );
if(errMsg != null ) {
return Optional.of(errMsg);
}
return Optional.empty();
}
/**** client usage ****/
ObjectToCheck obj = doSomethingToReadInput(obj);
Optional<String> error = checkForErrors( obj);
if (error.isPresent()) {
// invalid input, throw object away and request input again
} else {
// do stuff, we have a valid input
}
Чтобы исправить, начните с создания общего интерфейса, который будет представлять один валидатор.Затем каждая проверка преобразуется в экземпляр валидатора.Наконец, мы создаем список валидаторов и передаем его в код валидатора.
/** The common validator interface each validator will use */
private interface MyValidator {
public boolean isValid(ObjectToCheck obj);
public String getErrorMessage(ObjectToCheck obj);
}
// this method should look familiar to the above, now we
// have a list of validators as an additional parameter
public Optional<String> checkForErrors( ObjectToCheck objToCheck,
List<MyValidator> validators ) {
for(MyValidator validator : validators ) {
if (!validator.isValid(objToCheck)) {
String errMsg = validator.getErrorMessage(objToCheck);
return Optional.of(errMsg);
}
}
return Optional.empty();
}
/****** client usage *****/
// now in this pattern, the client controls when the validators
// are created, and which ones are used.
MyValidator validator1 = new MyValidator() {
@Override
public boolean isValid(ObjectToCheck obj) {
return checkForError1( objToCheck ) != null;
}
@Override
public boolean getErrorMessage(ObjectToCheck obj) {
return checkForError1( objToCheck );
}
}
// note: above we call checkForError1 twice, not optimal.
// typical in real examples this can be avoided,
// and the error message generation logic split from the detection
// logic often simplifies things.
MyValidator validator2 = new MyValidator() { ... }
List<MyValidator> validators =
ImmutableList.of( validator1, validator2);
Optional<String> error = checkForErrors(objToCheck, validators);
if (error.isPresent()) {
// invalid input, throw object away and request input again
} else {
// do stuff, we have a valid input
}
Теперь, чтобы протестировать, создайте серию фиктивных валидаторов и убедитесь, что у каждого из них есть свой валидатор.Вы можете заблокировать результаты валидатора и убедиться в правильности поведения.Затем у вас также есть доступ к каждому валидатору в отдельности, так что вы можете проверить их один за другим самостоятельно.Приветствия - надеюсь, что это помогает, счастливое кодирование.