本文正在参加「金石计划 . 分割6万现金大奖」

前语

​ 在事务场景中,咱们在针对用户还款的时分,需求对用户此次还款信息进行一系列的规矩校验,比如事务开关校验、还款在途校验、还款账户校验、产品事务规矩校验等等,只有契合规矩了,才允许你进行下一步的还款操作

​ 在当时咱们的中台完成中,咱们凭借流程编列来完成校验环节,即咱们会将一个个校验逻辑,拆成一个个节点来进行逻辑履行,简单一点了解,便是一个校验便是咱们代码中的一个 bean

​ 上图,阐明一下

设计模式组合拳,优化你的规则校验

​ 为了保持咱们流程的清爽以及减少项目现场施行同学的学习本钱,决定将通用的事务规矩校验进行整合,在流程编列中仅敞开一个节点 “还款校验” 节点,假如项目有个性化的校验节点可自主在该校验节点前后进行增加即可

普通完成

​ 简单来说,咱们要做的工作便是合并组件的事,将原先的四个组件合并成一个组件,那这不是手到擒来

设计模式组合拳,优化你的规则校验

​ 三下五除二,代码就完成完了

public Boolean checkRepayApply(CheckParam checkParam) {
    // 履行 A 规矩校验,校验失利即走向还款失利流程
    if (!checkA(checkParam)) {
        return repayApplyFail();
    }
    // 履行 B 规矩校验,校验失利即走向还款失利流程
    if (!checkB(checkParam)) {
        return repayApplyFail();
    }
    // 略
    if (!checkC(checkParam)) {
        return repayApplyFail();
    }
    // 略
    if (!checkD(checkParam)) {
        return repayApplyFail();
    }
    return Boolean.TRUE;
}

​ 代码完成 ✅

​ 提交测验 ✅

​ 下班 ✅

​ 可是这种完成逻辑,跑是能跑,可是假设咱们的校验逻辑一旦增加,后续接手的张三同学、李四同学就会看着满屏的 if,然后打开前史提交记载,顺着提交记载把每个人都 tui 一遍

​ 为了 防备被骂,以及体现咱们的技术水平,保持咱们的代码对关于扩展敞开,关于修改封闭,优雅咱们的代码完成,咱们需求针对这段代码进行重构,让这一段代码香起来

设计模式组合拳,优化你的规则校验

优雅完成

​ 面对这种串联的事务履行,咱们能够凭借到咱们的 “职责链” 设计形式,这种设计形式比较好了解,咱们举个例子

​ 有一天,你要请假去相亲,于是你在 OA 上提交了请假申请,需求经过小组组长、部分主管、部分经理,小组组长批假、部分主管批假、部分经理不批假,于是你相亲失利

设计模式组合拳,优化你的规则校验

​ 职责链形式便是用于咱们这种链条式的处理一个恳求,对比咱们还款中的校验是不是就能够彻底套用了

​ 职责链形式的精髓在于它能够指定一个处理该恳求的是那个履行器,那么咱们的伪代码应该是这样的

AHandler aHandler = new AHandler();
BHandler bHandler = new BHandler();
CHandler cHandler = new CHandler();
aHandler.setNextRule(bHandler);
bHandler.setNextRule(cHandler);
aHandler.execute();

​ 看起来有点糟糕,这一段代码像不像咱们在 new 出来一个目标的时分,不断进行 set 字段的时分,咱们一般凭借的是 lombok 去进行字段的 build,去简练咱们的代码,于是咱们能够凭借这种“build”思维,运用“制作者”这种设计形式,去把咱们的履行器一个个 build 出来

​ 主意基本已经有了,接下来咱们开端写 bug 逻辑

一致接口

咱们需求写一个接口,让现在以及未来的规矩履行器都一致完成该接口,去完成固定的接口

public interface IRule{
    /**
     * 规矩履行
     *
     * @param t 校验参数
     * @return 履行成果
     */
    CheckResultDto execute(CheckParam t);
    /**
     * 指定下一个履行器
     *
     * @param supplier 运用其来创建目标
     * @return 规矩履行器
     */
    IRule nextRule(Supplier<IRule> supplier);
}

这边咱们能够注意到咱们指定下一个履行器是运用的 Supplier 接口,弥补阐明一句 Supplier 是 Java8 提供给咱们的一个接口目标,最大的特点是懒加载,咱们运用其来指定履行器也是为了去简练咱们的代码,当然在这边 nextRule 的入参直接为 IRule 目标也是能够的

规矩完成

​ 咱们先写一个 Rule1 履行器,去完成咱们的的 IRule 接口

​ execute 办法是咱们的详细事务履行逻辑,当咱们此次规矩履行经过而且下一个履行器不为空的时分咱们就进行下一个履行器的事务逻辑,假如下一个履行器为空,咱们就直接 retun 履行成果就好了

​ nextRule 办法是咱们指定下一个履行器是什么

public class Rule1 implements IRule {
    private IRule nextRule;
    @Override
    public CheckResultDto execute(CheckParam t) {
        System.out.println("榜首个履行器运转中");
        if (t.getCheckFlag() && (Objects.nonNull(nextRule))) {
            return nextRule.execute(t);
        }
        return CheckResultDto.builder().result("我是榜首个履行器的输出").build();
    }
    @Override
    public IRule nextRule(Supplier<IRule> supplier) {
        this.nextRule = supplier.get();
        return nextRule;
    }
}

​ 其他的规矩履行器咱们仿制这个写就好了,这边就不开冗余阐明了

测验办法

public class Test {
    public static void main(String[] args) {
        CheckParam checkParam = new CheckParam();
        checkParam.setCheckFlag(Boolean.TRUE);
        Rule1 rule1 = new Rule1();
        rule1.nextRule(Rule2::new).nextRule(Rule3::new);
        CheckResultDto execute = rule1.execute(checkParam);
        System.out.println(execute.toString());
    }
}
// 输出成果
榜首个履行器运转中
第二个履行器运转中
第三个履行器运转中
CheckResultDto{result='我是第三个履行器的输出'}

总结

​ 至此,咱们的重构已经完毕,咱们回忆一下大体的完成逻辑

​ step1:编写 IRule 接口,指定事务逻辑履行办法 execute ,下一个履行器 nextRule 办法

​ step2:完成 IRule 接口,编写详细事务逻辑

​ step3:调用规矩进行履行校验

​ 全体步骤其实很简单,可是大大优化了咱们代码的可读性以及拓宽才能,可支持校验组件拆卸组装,每一段代码都是由每一小行进行完成的,逐步优化好每一段代码,才能够防止咱们shi山的累积

​ 这一部分轮子直接搬出来就可运用,所有源代码地址均在:github.com/isysc1/Issu…

闲言碎语

​ 周五在我骑着小毛驴上班的时分

​ 忽然捡到了一个手机,本着拾机不昧的准则,我在原地等了五分钟,发现失主还不给我打电话

​ 我就拿着手机去了公司,本着严谨的准则我准备报个警,将手机交给差人叔叔,差人肯定会接过我的手机,然后对我给我竖一个大拇指,嗯,不错

​ 刚准备打我人生榜首通报警电话,成果失主打电话进来了,很着急的姿态,然后咱们沟通了地点,我准备把手机还给她

​ 和失主交流了一下,确认了手机解锁暗码,失主说今天刚好仍是她生日,还留了我手机号,要请我喝奶茶

​ 虽然一天过去了,还没加我微信,可是想想我捡到手机也不是图人家的报答啥的,今天肯定仍是失主最难忘的一次生日了,又是日行一善的一天 over