Является ли хорошая ставка для крупной проверки?

Мне нужно построить процесс, который будет проверять запись по ~200 правилам проверки. Запись может быть одного из ~10 типов. Существует некоторая сегментация от правил валидации до типов записей, но существует много совпадений, которые мешают мне корректно объединить правила валидации.

Во время разработки я рассматриваю схему цепочки ответственности для всех правил валидации. Это хорошая идея или лучший шаблон дизайна?

2 ответа

Проверка часто является составным шаблоном. Когда вы разбиваете это на части, вы хотите отделить то, что вы хотите, от того, как вы хотите это сделать, вы получите:

Если foo действителен, тогда сделайте что-нибудь.

Здесь у нас есть действительная абстракция - Caveat: этот код был взят из текущего, подобных примеров, так что вы можете найти недостающие символы и тому подобное. Но это так, вы получите картину. В дополнение

Result

Объект содержит сообщения о сбое, а также простой статус (true/false). Это позволяет вам просто спросить "прошло?" против "Если это не удалось, скажите мне, почему"

QuickCollection

а также

QuickMap

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

У вас возникла вторичная проблема в вашем вопросе: "чисто связывание", как в "Типе A" -> правилах {a,b,c}"и" Типе B" -> правилах {c,e,z}"

Это легко сделать с помощью карты. Не совсем шаблон Command, но близко

Map<Type,Validator> typeValidators = new HashMap<>();

Установите валидатор для каждого типа, а затем создайте сопоставление между типами. Это действительно лучше всего сделать в качестве конфигурации бина, если вы используете Java, но определенно используете внедрение зависимостей

    public interface Validator<T>{


    public Result validate(T value);


    public static interface Result {

        public static final Result OK = new Result() {
            @Override
            public String getMessage() {
                return "OK";
            }

            @Override
            public String toString() {
                return "OK";
            }

            @Override
            public boolean isOk() {
                return true;
            }
        };

        public boolean isOk();

        public String getMessage();
    }
    }

Теперь несколько простых реализаций, чтобы показать суть:

public class MinLengthValidator implements Validator<String> {

private final SimpleResult FAILED;

private Integer minLength;

public MinLengthValidator() {
    this(8);
}

public MinLengthValidator(Integer minLength) {
    this.minLength = minLength;
    FAILED = new SimpleResult("Password must be at least "+minLength+" characters",false);
}

@Override
public Result validate(String newPassword) {
    return newPassword.length() >= minLength ? Result.OK : FAILED;
}

@Override
public String toString() {
    return this.getClass().getSimpleName();
}
}

Вот еще один, с которым мы совместим

public class NotCurrentValidator implements Validator<String> {

    @Autowired
    @Qualifier("userPasswordEncoder")
    private PasswordEncoder encoder;

    private static final SimpleResult FAILED = new SimpleResult("Password cannot be your current password",false);

    @Override
    public Result validate(String newPassword) {
        boolean passed = !encoder.matches(newPassword,user.getPassword());
        return (passed ? Result.OK : FAILED);
    }

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }

}

Теперь вот составной:

public class CompositePasswordRule extends QuickCollection<Validator> implements Validator<String> {


public CompositeValidator(Collection<Validator> rules) {
    super.delegate = rules;
}

public CompositeValidator(Validator<?>... rules) {
    super.delegate = Arrays.asList(rules);
}



@Override
public CompositeResult validate(String newPassword) {
    CompositeResult result = new CompositeResult(super.delegate.size());
    for(Validator rule : super.delegate){
        Result temp = rule.validate(newPassword);
        if(!temp.isOk())
            result.put(rule,temp);
    }

    return result;
}


    public static class CompositeResult extends QuickMap<Validator,Result> implements Result {
        private Integer appliedCount;

        private CompositeResult(Integer appliedCount) {
            super.delegate = VdcCollections.delimitedMap(new HashMap<PasswordRule, Result>(), "-->",", ");
            this.appliedCount = appliedCount;
        }

        @Override
        public String getMessage() {
            return super.delegate.toString();
        }

        @Override
        public String toString() {
            return super.delegate.toString();
        }

        @Override
        public boolean isOk() {
            boolean isOk = true;
            for (Result r : delegate.values()) {
                isOk = r.isOk();
                if(!isOk)
                    break;
            }
            return isOk;
        }
        public Integer failCount() {
            return this.size();
        }

        public Integer passCount() {
            return appliedCount - this.size();
        }
    }
}

и теперь фрагмент использования:

private Validator<String> pwRule = new CompositeValidator<String>(new MinLengthValidator(),new NotCurrentValidator());

Validator.Result result = pwRule.validate(newPassword);
if(!result.isOk())
    throw new PasswordConstraintException("%s", result.getMessage());

user.obsoleteCurrentPassword();
user.setPassword(passwordEncoder.encode(newPassword));
user.setPwExpDate(DateTime.now().plusDays(passwordDaysToLive).toDate());
userDao.updateUser(user);

Цепочка ответственности подразумевает наличие порядка, в котором должны проводиться проверки. Я бы, вероятно, использовал что-то похожее на шаблон "Стратегия", где у вас есть набор стратегий проверки, которые применяются к конкретному типу записи. Затем вы можете использовать фабрику для проверки записи и применения правильного набора проверок.

Другие вопросы по тегам