• 代码改造:设计模式之责任链



    theme: cyanosis
    highlight: a11y-dark

    前言


    最近负责了一个相对大点的项目,在开发的时候一把梭哈,最近在做代码优化(个人习惯是开发时把逻辑快速搞完,很多实现方式在设计阶段已经拍板,不会有太大问题,然后等开发完后再开始做精修)

    发现了一个很长的逻辑,有190行,包括注释、换行还有代码,那么如何进行代码优化呢?

    灵感


    在看阿里的一个设计方案的时候,找到一个灵感,就是凑单很多数据都是别人的,互相不影响,只是将数据进行拼接,采用了责任链的形式,就是每个处理器都能处理到,然后进行加工,最后得到一个结果。

    将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。

    责任链


    第一次接触责任链是在网关层,globalFilter,网关会有filter链条,每个拦截器会有自己的逻辑,比如说限流、权限、参数打印等等逻辑,如果其中一个处理器不通过则中断请求。

    我们这个功能有所不同的是:并不是其中一个处理器不通过就中断,而是没有就跳过处理,进入下一个处理器进行加工,直到所有的处理器加工完成整个处理流程。有点像车间流水线,一个环节装一点,然后拼接成一辆车。

    实践

    业务背景

    一个定时器处理拉取数据的逻辑,设计到4个模块

    定义处理器

    有处理方法,然后有另外一个标识当前处理器是什么类型

    /**
     * 定时器处理器
     */
    public interface Processor {
    
        /**
         * 加工处理过程
         *
         * @param exchange
         */
        void process(ChainExchange exchange);
    
        /**
         * 类型
         *
         * @return
         */
        ProcessorType type();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    链条中上下文

    这里定义的是传递数据,比如说最终加工成一辆车,就是传递一整车的数据,车顶、轮毂…

    /**
     * 链条交换数据
     */
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class ChainExchange {
    
    /**
    * 上下文传递的参数
    **/
        private xx xx;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    处理器枚举

    @Getter
    @AllArgsConstructor
    public enum ProcessorType {
    
        /**
         * 处理器枚举值
         */
        
        xx("xx处理器");
    
        /**
         * 状态
         */
        private String message;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    定义相应处理器

    这里定义链条中某个处理器的处理逻辑,还有标识

    /**
     * 账单附件处理器
     */
    @Component
    public class xxProcessor implements Processor {
    
        @Override
        public void process(ChainExchange exchange) {
            
        }
    
        @Override
        public ProcessorType type() {
            return ProcessorType.xx;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    装订整个链条

    /**
     * 处理链条汇总
     */
    @Component
    public class ProcessorChain implements InitializingBean {
    
        @Resource
        private List formFacadeList;
    
        /**
         * 处理器链条
         */
        private final List processorList = new ArrayList<>();
    
        private void init() {
            //初始化处理链条 xx->xx->xx
            processorList.add(formFacadeList.stream().filter(it -> ProcessorType.BILL.equals(it.type())).findFirst().get());
        }
    
        /**
         * 处理数据
         */
        public void handleData(xx xx) {
    
            //处理节点下标
            int index = 0;
    
            //上下文传递内容
            ChainExchange exchange = ChainExchange.builder().build();
    
            while (index < processorList.size()) {
                Processor processor = processorList.get(index);
                processor.process(exchange);
    
                index++;
            }
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            init();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    到这里所有处理器的链条装订完毕,我们只需执行这整个链条即可,等待流水线的加工完毕。

    责任链好处


    从一个方法190行代码,到拆分成4个类,每个类的逻辑都是一个模块的,这样代码的可读性是提高了,然后扩展性比较好的,比如说某个模块需要改造,可以避免代码的遗漏。

    就像车顶加工流程需要优化,我们只改车顶加工节点的逻辑。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lX19f4BJ-1660034289687)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b5cbe7ed3e6445e2810cfc095d9bc04a~tplv-k3u1fbpfcp-watermark.image?)]

  • 相关阅读:
    java毕业生设计圆梦酒店管理系统计算机源码+系统+mysql+调试部署+lw
    StarRocks 中的数据模型、索引
    Go 之常用并发学习
    selenium headless 无头模式慢
    漏洞复现--泛微E-Office前台文件读取漏洞
    设备间同步的电子书阅读器--查找未果
    Spring Security认证之基本认证
    C Primer Plus(6) 中文版 第9章 函数 9.2 ANSI C 函数原型
    【LeetCode】146.LRU缓存
    洛谷刷题笔记 确定进制
  • 原文地址:https://blog.csdn.net/weixin_38336658/article/details/126250784