对于一个大的验证任务是责任链模式的一个好赌注?

时间:2014-05-01 13:42:50

标签: java design-patterns chain-of-responsibility

我需要构建一个过程,该过程将根据~200个验证规则验证记录。记录可以是~10种类型中的一种。从验证规则到记录类型有一些细分,但存在大量重叠,这使我无法对验证规则进行干净整理。

在我的设计过程中,我考虑了所有验证规则的责任链模式。这是一个好主意还是有更好的设计模式?

2 个答案:

答案 0 :(得分:16)

验证通常是复合模式。当你将其分解时,你想要从你想要的中分离你想要的 ,你得到:

如果foo有效 然后做点什么。

这里我们有抽象是有效的 - 警告:这个代码是从类似的例子中解除的,所以你可能会发现缺少符号系统等等。但这是你得到的照片。另外,

Result

对象包含有关失败的消息以及简单状态(true / false)。 这允许您选择只是询问它是否通过了?" vs."如果失败了,请告诉我为什么"

QuickCollection

QuickMap

是用于获取任何课程的便利课程,并通过仅仅分配给一个代表来快速将它们变成那些受尊重的类型。对于此示例,这意味着您的复合验证器已经是一个集合,并且可以进行迭代,例如。

您的问题中存在次要问题:"干净利落的问题"如," A型和#34; - >规则{A,B,C}"和" B" - >规则{C,E,Z}"

使用Map可以轻松管理。不完全是Command pattern但是关闭

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

为每种类型设置验证器,然后在类型之间创建映射。如果您使用Java但绝对使用dependency injection

,那么最好以bean配置完成
    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);

答案 1 :(得分:4)

责任链意味着必须进行验证。我可能会使用类似于策略模式的东西,其中有一组应用于特定记录类型的验证策略。然后,您可以使用工厂检查记录并应用正确的验证集。