责任链模式在字段验证场景中的使用


责任链模式在字段验证场景中的使用

最近在搬砖过程中有一个保存大表单的需求(搬砖CRUD常态),在保存这个大表单之前有一系列的检验(字段校验使用了JSR303),表单名不能和已有的重名、表单数量、同时还有一些字段是互斥不能同时选择的等等一些情况。

当时做这个的时候直接if else一把梭了,不过写到后面发现满屏的if else怎么看怎么别扭。

public boolean validate(Query query) {
    if (表单名验证){

    } else if (表单数量验证) {

    } else if (时间校验) {

    }
    ...
}

责任链模式

顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

​ 来源:https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html

简而言之,责任链模式就是一个对象经过一系列链接成链条的处理对象从而进行一系列处理。

从上面的定义可以看出责任链模式非常适合用来对同一个对象进行一系列处理的场合,如SpringMVC的拦截器使用场景,对Request进行拦截处理。对表单对象进行检验的场景也非常适合使用责任链模式。

代码实现

在校验场景中,待处理对象就是表单对象,一系列的进行处理的对象则是一系列的校验器。因此首先需要一个校验器的接口,如下:

public interface Validator {
    ValidateResult validate(ReportQuery reportQuery);
}

对表单进行校验的校验器通过实现Validator接口即可:

// 表单名验证
public class ReportNameValidator implements Validator {

    @Override
    public ValidateResult validate(ReportQuery reportQuery) {
        // 表单名校验逻辑
    }
}

// 表单数量验证
public class ReportSizeValidator implements Validator {

    @Override
    public ValidateResult validate(ReportQuery reportQuery) {
        // 表单数量校验逻辑
    }
}

链条上的进行处理的对象已经有了,现在需要一个可以把这些处理对象链接起来的并且可以按照链条顺序一一执行校验的对象:

public class ReportValidator {
    // 检验器集合
    private List validators = new ArrayList<>();

    // 添加校验器并链接成链条
    public ReportValidator addValidator(Validator validator) {
        validators.add(validator);
        return this;
    }

    // 按照链条顺序执行校验
    public ValidateResult validate(ReportQuery reportQuery) {
        ValidateResult validateResult = null;
        for (Validator validator : validators) {
            validateResult = validator.validate(reportQuery);
            if (!validateResult.isSuccess()) {
                return validateResult;
            }
        }
        return validateResult;
    }

}

然后,使用起来是这样子的:

    @PostMapping("/urlpath")
    public JsonCommonResponse fun(@RequestBody ReportQuery reportQuery) {
        // 校验
        ReportValidator reportValidator = new ReportValidator().addValidator(new ReportNameValidator())
                .addValidator(new ReportSizeValidator());
        ValidateResult validateResult = reportValidator.validate(reportQuery);
        if (!validateResult.isSuccess()) {
            return JsonCommonResponse.failRes(validateResult.getResultCode());
        }
        // 业务逻辑
    }

这样子使用起来十分方便,而且可读性也很好,扩展也十分方便,如果有新的校验逻辑,新建一个检验器类,添加到链条中即可。

注:一些校验器的检验逻辑可能会依赖它前面的校验结果,可能会导致NPE(检验器的添加顺序也请务必仔细考虑)

总结

责任链模式非常适合用于对一个对象进行一系列的处理,如过滤(过滤器),拦截(拦截器),检验(检验器)。

表单校验使用责任链模式和JSR303配合校验十分方便,而且可读性可维护性扩展性都挺不错。


文章作者: Ning0h2o
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ning0h2o !
评论
评论
 上一篇
位移在枚举中的应用 位移在枚举中的应用
位移在枚举中的应用最近在公司代码中发现一个枚举类中使用了位移来表示枚举值,不是很能理解为何这样设置,遂去问了度娘和老同事。大概意思就是存在多个枚举组合使用的情况下使用位移能很方便的分辨出是哪些枚举。 public enum Business
2020-09-06
下一篇 
Ning0h2o的第一篇Blog Ning0h2o的第一篇Blog
Ning0h2o的第一篇Blog,关于我写博客的一些理由
2020-08-23
  目录