简谈设计模式-责任链模式

2021-10-01   


概述

责任链模式在各类开源框架中非常常见。rpc远程调用、http调用等都大量使用了责任链模式来进行代理调用。
责任链模式将顺序或嵌套代码逻辑进行抽象拆分为一个个结点,来进行链式调用,不同于命令模式使用额外的命令执行器来进行执行,责任链的入口是链表头结点的调用,后续每个结点的调用,由上一个结点来代理调用,也就是上一个结点有后续所有调用的控制权,它可以终止后续调用,或者在后续调用后做一些清理动作等,常用来实现日志监控、限流、拦截等功能。

实战

public class ChainTest {
    // 每一个责任链结点都有指向下一个责任链结点的指针
    class FilterSlot{
        private FilterSlot next;
        // 下一个调用前做什么可以覆盖此方法
        public void before(Context context){
        }

        // 下一个调用后做什么可以覆盖此方法
        public void after(Context context){
        }

        public void invoke(Context context){
            before(context);
            // 上下文托管到next结点去invoke
            fireNext(context);
            after(context);
        }

        public void fireNext(Context context){
            if(this.next != null){
                this.next.invoke(context);
            }
        }
    }

    // 给链表结点包装一下,方便组成链表
    class FilterSlotChain extends FilterSlot{
        FilterSlot first = new FilterSlot(); // 一个虚拟头结点
        FilterSlot end = first;

        @Override
        public void invoke(Context context){
            if(end == first){
                return;
            }
            first.next.invoke(context);
        }

        // 追加结点往链表尾部追加
        public void addLast(FilterSlot filterSlot){
            end.next = filterSlot;
            end = filterSlot;
        }
    }

    class FilterSlotSubA extends FilterSlot{

        @Override
        public void invoke(Context context){
            Long start = System.currentTimeMillis();
            if(super.next != null){
                super.next.invoke(context);
            }
            Long end = System.currentTimeMillis();
            // 统计后续调用总耗时
            System.out.println("elapsed time mills:" + (end-start));
        }
    }

    class FilterSlotSubB extends FilterSlot{
        @Override
        public void before(Context context){
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e){

            }
            System.out.println("SlotB before");
        }
    }

    // 再来一个ChainBuilder负责责任链的构建
    class DefaultFilterSlotChainBuilder{

        public FilterSlotChain build(){
            FilterSlotChain chain = new FilterSlotChain();
            chain.addLast(new FilterSlotSubA()); // 添加子类实例
            chain.addLast(new FilterSlotSubB()); // 添加子类实例
            return chain;
        }
    }

    class Context{
    }

    public void testMain(){
        FilterSlotChain chain = new DefaultFilterSlotChainBuilder().build();
        Context context = new Context();
        // 责任链的调用
        chain.invoke(context);
    }

    public static void main(String[] args){
        new ChainTest().testMain();
    }
}

Q.E.D.