重构业务逻辑验证

时间:2017-08-17 15:01:44

标签: java validation java-8

我试图重构此代码

private void validate(Customer customer) {

    List<String> errors = new ArrayList<>();

    if (customer == null) {
        errors.add("Customer must not be null");
    }

    if (customer != null && customer.getName() == null) {
        errors.add("Name must not be null");
    }

    if (customer != null && customer.getName().isEmpty()) {
        errors.add("Name must not be empty");
    }

    if (customer != null) {
        Customer customerFromDb = customerRepository.findByName(customer.getName());
        if (customerFromDb != null) {
            errors.add("Customer already present on db");
        }
    }

    if (!errors.isEmpty()) {
        throw new ValidationException(errors);
    }
}

我读过这篇文章Business logic validation patterns & advices

我想为我的实体和实体字段构建一个通用验证器,我写了这个

private void validate(Customer customer) {

    List<ValidationRule> validationRules = new ArrayList<>();

    validationRules.add(new NotNullValidationRule(customer));
    validationRules.add(new NotNullValidationRule(customer, Customer::getName));
    validationRules.add(new NotEmptyValidationRule(customer, Customer::getName));
    validationRules.add(new NotExistValidationRule(customer -> customerRepository.findByName(customer.getName())));

    Validator.validate(validationRules);
}

和Validator类

public class Validator {

    public static void validate(List<ValidationRule> validationRules) {
        final List<String> errors = new ArrayList<>();
        for (final ValidationRule rule : validationRules) {
            final Optional<String> error = rule.validate();
            if (error.isPresent()) {
                errors.add(error.get());
            }
        }

        if (!errors.isEmpty()) {
            throw new ValidationException(errors);
        }
    }
}

但我不知道如何实现接口ValidationRule和其他类(NotNullValidationRule,NotEmptyValidationRule,NotExistValidationRule)

3 个答案:

答案 0 :(得分:0)

我会写一些类似的东西:

CommonValidations.notNull(errors, customer);
if (customer != null) {
    CommonValidations.notEmpty(errors, customer.getName());
}
customerCustomeBeanValidations.validName(errors, customer.getName());
customerCustomeBeanValidations.notExist(errors, customer.getName());

答案 1 :(得分:0)

在您引用的链接中,使用Strategy设计模式建议接受的答案,然后举例说明接口和实现。在您的情况下,您将创建一个新的接口ValidationRule,至少有一个方法validate(),然后您将创建每个实现该接口的具体类(NotNullValidationRule,NotEmptyValidationRule,AlreadyExistValidationRule)。

答案 2 :(得分:0)

我找到了这个解决方案:

我创建一个接口ValidationRule

import java.util.Optional;

public interface ValidationRule {
    Optional<ValidationError> validate();
}

以及一些实现行为的类

public class NotNullValidationRule implements ValidationRule {

    private Object object;
    private String field;

    public NotNullValidationRule(Object object, String field) {
        this.object = object;
        if (field == null || field.isEmpty()) {
            throw new IllegalArgumentException("field must not be null or emtpy");
        }
        this.field = field;
    }

    @Override public Optional<ValidationError> validate() {

        if (object == null) {
            return Optional.empty();
        }

        try {
            Object value = new PropertyDescriptor(field, object.getClass()).getReadMethod().invoke(object);
            if (value == null) {
                ValidationError validationError = new ValidationError();
                validationError.setName(object.getClass().getSimpleName() + "." + field);
                validationError.setError("Field " + field + " is null");
                return Optional.of(validationError);
            }
        }
        catch (Exception e) {
            throw new IllegalStateException("error during retrieve of field value");
        }

        return Optional.empty();
    }
}

另一个我传递方法调用的地方:

package it.winetsolutions.winactitime.core.service.validation;

import java.beans.PropertyDescriptor;
import java.util.Optional;
import java.util.function.Function;

public class NotExistValidationRule implements ValidationRule {

    Object object;
    String field;
    Function<? super String, ? super Object> function;

    public NotExistValidationRule(Object object, String field, Function<? super String, ? super Object> function) {
        this.object = object;
        if (field == null || field.isEmpty() || function == null) {
            throw new IllegalArgumentException("field and function must not be null or emtpy");
        }
        this.field = field;
        this.function = function;
    }

    @Override public Optional<ValidationError> validate() {

        if (object == null) {
            return Optional.empty();
        }

        try {
            Object value = new PropertyDescriptor(field, object.getClass()).getReadMethod().invoke(object);
            Long id = (Long) new PropertyDescriptor("id", object.getClass()).getReadMethod().invoke(object);
            Object result = function.apply(value == null ? (String) value : ((String) value).trim());
            if (result != null &&
                !id.equals((Long) new PropertyDescriptor("id", result.getClass()).getReadMethod().invoke(result))) {
                ValidationError validationError = new ValidationError();
                validationError.setName(object.getClass().getSimpleName() + "." + field);
                validationError.setError("Element with " + field +": " + value + " already exists");
                return Optional.of(validationError);
            }
        }
        catch (Exception e) {
            throw new IllegalStateException("error during retrieve of field value");
        }

        return Optional.empty();
    }
}