把书读薄 | 《设计模式之美》设计模式与范式(行为型-责任链模式)(上)

简介: 本文对应设计模式与范式:行为型(62-63),责任链模式 (Chain of Responsibility Pattern),常用于框架开发中,为框架提供扩展点,让框架使用者在不修改框架源码的情况下,基于扩展点添加新的功能,具体点说,最常用来开发框架的 拦截器 和 过滤器。

0x1、定义


原始定义


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


定义看起来有点抽象,简单点就是:构建一个处理流水线来对一次请求进行多次处理

还是不懂?没关系,写个简单例子帮助理解~


0x2、写个简单例子


你问哥哥、粑粑、麻麻拿钱,门槛依次是100,500,1000,只能按照一层层往下走,比如:


100块以下的开销,你可以找哥哥解决,100以上500以下的你得找爸爸,500以上1000以下你得找麻麻~


直接if-else一把梭,不难写出这样的代码:


public class ChainTest {
    public static void main(String[] args) {
        Random random = new Random();
        int needMoney = random.nextInt(1500);
        System.out.println("需要:" + needMoney + "块~");
        if(needMoney < 100) {
            System.out.println("哥哥:小于100块哥哥还是有的,给你~");
        } else {
            System.out.println("哥哥:大于100块哥哥木有那么多钱,找粑粑去吧~");
            if(needMoney < 500) {
                System.out.println("粑粑:500块以内,粑粑有,给你~");
            } else {
                System.out.println("粑粑:大于500,粑粑木有,找妈妈去吧~");
                if(needMoney < 1000) {
                    System.out.println("麻麻:1000以内,麻麻可以报销,给你~");
                } else {
                    System.out.println("麻麻:你要那么多钱干嘛?");
                }
            }
        }
    }
}


代码运行输出结果如下


网络异常,图片无法展示
|


如果再来个疼爱孙子的爷爷,超过1000的可以找他报销,又得嵌套一个if-else,在一些复杂的实际业务场景,这样的写法可能要套十几层,对于这种流水线式加工的场景,其实可以使用责任链模式解耦~


把伸手要钱这个行为看成一个 请求,你是 请求者,家人是 接收者,他们会按照特定的顺序:哥哥 → 粑粑 → 麻麻 → 爷爷 对你的请求进行处理,在自己额度范围内,就不往下走,不在就往下走,直到最后一个接收者为止。这个特定顺序可以看成一条 ,请求就是沿着这样的链往后传递~


一种最简单的实现方式,就是:每个接收者持有后继接收者实例,递归调用直到没有后继接收者为止,实现代码如下:


// 抽象处理者
public abstract class AbstractHandler {
    // 下一个处理者
    private AbstractHandler nextHandler;
    public AbstractHandler getNextHandler() { return nextHandler; }
    public void setNextHandler(AbstractHandler nextHandler) { this.nextHandler = nextHandler; }
    // 请求处理
    public abstract void handleRequest(String msg, int money);
}
// 具体处理者
public class BrotherHandler extends AbstractHandler {
    @Override
    public void handleRequest(String msg, int money) {
        System.out.println(msg + ":" + money + "块~");
        if(money < 100) {
            System.out.println("哥哥:小于100块哥哥还是有的,给你~");
        } else {
            System.out.println("哥哥:大于100块哥哥木有那么多钱,找粑粑去吧~");
            if(getNextHandler() != null) getNextHandler().handleRequest(msg, money);
        }
    }
}
public class FatherHandler extends AbstractHandler {
    @Override
    public void handleRequest(String msg, int money) {
        if(money < 500) {
            System.out.println("粑粑:500块以内,粑粑有,给你~");
        } else {
            System.out.println("粑粑:大于500,粑粑木有,找妈妈去吧~");
            if(getNextHandler() != null) getNextHandler().handleRequest(msg, money);
        }
    }
}
public class MotherHandler extends AbstractHandler {
    @Override
    public void handleRequest(String msg, int money) {
        if(money < 1000) {
            System.out.println("麻麻:1000以内,麻麻可以报销,给你~");
        } else {
            System.out.println("麻麻:你要那么多钱干嘛?");
            if(getNextHandler() != null) getNextHandler().handleRequest(msg, money);
        }
    }
}
// 测试用例
public class ChainTest {
    public static void main(String[] args) {
        Random random = new Random();
        int needMoney = random.nextInt(1500);
        BrotherHandler brotherHandler = new BrotherHandler();
        FatherHandler fatherHandler = new FatherHandler();
        MotherHandler motherHandler = new MotherHandler();
        // 指定下一个接收者
        brotherHandler.setNextHandler(fatherHandler);
        fatherHandler.setNextHandler(motherHandler);
        // 开始请求传递
        brotherHandler.handleRequest("狗子要钱", needMoney);
    }
}


代码运行结果输出如下


网络异常,图片无法展示
|


责任链模式解耦后,此时我们要再添加一个爷爷就很简单了,四步:


继承AbstractHandler → 重写handleRequest() → 初始化爷爷实例 → motherHandler.setNextHandler()


如果要再来个曾祖父或高曾祖父,也是这样操作,你可能会吐槽是不是有点过度设计,简单的if-else嵌套就能解决,这样会写多很多类,有点复杂化了。


应用设计模式主要是为了:应付代码复杂性,让其满足开闭原则,提高代码扩展性。而将大块代码逻辑拆解成函数、大类拆分成小类,是应对代码复杂性的常用方法。


此处使用责任链模式,把处理请求的函数拆分出来,设计成独立的类,简化了ChainTest类,使其不至于代码过多,过复杂。


客户端代码新增一个接收者,不需要去修改框架的代码,只需基于框架提供的扩展点进行扩展,可以说是:在框架代码范围内实现了开闭原则


老规矩,带出UML类图、组成角色、使用场景及优缺点的总结


网络异常,图片无法展示
|


  • Handler (抽象处理者) → 定义了处理请求的接口或抽象类,提供处理请求的方法和设置下一个处理者的方法;
  • ConcreteHandler (具体处理者) → 抽象处理者的具体实现,按照链条顺序对请求进行具体处理;


使用场景


  • 运行时需要动态使用多个关联对象来处理同一次请求,如编译打包发布流程;
  • 不想让使用者知道具体的处理逻辑,如权限校验的登录拦截器;
  • 需动态替换流程处理中的流程对象;
  • if-else多层嵌套或冗长的switch结构解耦;


优点


  • 降低客户端(请求者)与处理链条上对象(接收者)间的耦合度;
  • 动态组合,简化了对象前后关联处理的复杂性,只需存储一个指向后继者的引用;
  • 扩展灵活,新增具体请求者时无需修改原有系统的代码,满足开闭原则;


缺点


  • 产生许多细颗粒对象;
  • 比较长的责任链,可能涉及多个处理对象,可能存在性能问题,及调试不方便;
  • 建链不当,可能造成循环调用,导致死循环,进而导致堆栈溢出错误;


另外,除了使用上述 递归的方式形成链条 实现责任链模式外,还可以使用数据结构(数组、列表、链表等) 按顺序保存具体处理者实例,然后遍历的方式实现~


相关文章
|
22天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
54 9
|
10天前
|
设计模式 JavaScript Scala
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
26 0
|
21天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
本教程详细讲解了Kotlin语法,适合需要深入了解Kotlin的开发者。对于希望快速上手Kotlin的读者,推荐查阅“简洁”系列教程。本文通过学生会经费申请的例子,介绍了责任链模式及其在Kotlin中的实现,并使用偏函数进行了改进,使代码更加简洁和灵活。
11 0
|
24天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
37 0
|
1月前
|
设计模式 JavaScript Scala
Kotlin学习笔记 - 改良设计模式 - 责任链模式
Kotlin学习笔记 - 改良设计模式 - 责任链模式
42 0
|
2月前
|
设计模式 缓存 监控
Java设计模式-责任链模式(17)
Java设计模式-责任链模式(17)
|
1月前
|
设计模式 JavaScript Scala
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
25 0
|
5月前
|
设计模式 算法
行为型设计模式之模板模式
行为型设计模式之模板模式
|
5月前
|
设计模式 Java 中间件
深入探索Java设计模式:责任链模式解析与实践
深入探索Java设计模式:责任链模式解析与实践
55 0
|
5月前
|
设计模式 Java
Java设计模式之责任链模式详解
Java设计模式之责任链模式详解