责任链模式【Chain of Responsibility Pattern】,什么是责任链模式?核心思想?结构?作用?优缺点?实现案例?

目录


设计模式专栏目录(点击进入…)



什么是责任链模式?

责任链模式是一种行为型设计模式,它允许多个处理对象(处理器)有机会处理请求,而无需指定请求的具体接收者。处理器形成一条链,每个处理器都包含对下一个处理器的引用,当一个处理器无法处理请求时,它会将请求传递给链中的下一个处理器。责任链模式的核心思想是将请求的发送者与接收者解耦,使得多个对象都有机会处理请求。


责任链模式的核心思想

责任链模式通过将请求的处理逻辑进行解耦,让请求在一系列处理器中传递,直到找到能够处理它的对象,或者到达链的末尾。每个处理器既可以处理请求,也可以将其传递给下一个处理器,从而形成一种灵活的处理流程。


责任链模式的结构

(1)抽象处理者(Handler)

定义了处理请求的接口,并保存对下一个处理者的引用(通常通过设置 setNextHandler() 来传递请求)。抽象处理者通常包含一个处理请求的方法,如 handleRequest()。

(2)具体处理者(ConcreteHandler)

继承自抽象处理者,具体实现了处理请求的逻辑。如果当前处理者无法处理请求,则将请求传递给下一个处理者。

(3)客户端(Client)

发起请求的对象,客户端只需将请求发送给链中的第一个处理者,而不需要关心请求会被哪个处理者处理。


责任链模式的UML类图

+------------------+      +--------------------+       +--------------------+
|   Handler        |      | ConcreteHandler1   |       | ConcreteHandler2   |
|------------------|      |--------------------|       |--------------------|
| + setNextHandler()|      | + handleRequest()  |       | + handleRequest()  |
| + handleRequest()|----->| + setNextHandler()  |----->| + setNextHandler()  |
+------------------+      +--------------------+       +--------------------+

责任链模式的作用

(1)解耦请求的发送者与接收者

请求发送者只需知道链的第一个处理者,而不需要知道最终由谁处理请求。

(2)灵活地分配职责

通过动态设置责任链的顺序,责任链模式允许灵活地调整处理请求的责任分配。

(3)请求的链式传递

每个处理者都有机会处理请求,处理逻辑可以分布在多个对象中。


责任链模式的优缺点

优点

(1)降低耦合度

请求的发送者和处理者解耦,发送者无需知道是哪个处理者处理了请求。

(2)增强系统的灵活性

可以在运行时动态地调整责任链的结构(如:增加、删除或更改处理者的顺序)。

(3)符合单一职责原则

每个处理者只需处理自己能处理的部分,其他部分传递给下一个处理者,职责单一明确。

缺点

(1)可能导致请求无法处理

如果责任链没有合适的处理者,可能会导致请求无法得到处理,必须在设计时考虑这个问题。

(2)调试困难

由于请求可能经过多个处理者传递,责任链可能比较长,调试时难以跟踪请求的执行过程。

(3)性能开销

链条中的每个处理者都需要对请求进行处理或传递,链条过长可能导致性能问题。


责任链模式的应用场景

(1)审批流程

如上例所示,责任链模式广泛应用于各类审批系统,不同权限的审批者处理不同额度的请求。比如企业内部的请假审批、费用报销审批等。

(2)事件处理机制

在用户界面或操作系统中,事件(如点击、拖拽等)可以由责任链中的多个对象处理,如按钮、窗口、操作系统等。一个组件无法处理事件时,可以将事件传递给下一个组件。

(3)日志处理

责任链模式可以用于日志系统,不同的日志处理器可以处理不同等级的日志。例如,错误日志可以记录到文件中,调试日志则可以输出到控制台。

(4)Web请求处理

责任链模式在Web服务器中常用于请求的处理管道,如过滤器链(Filter Chain)。每个过滤器负责处理请求的某个方面(如权限验证、参数校验等),如果当前过滤器无法处理,可以将请求传递给下一个过滤器。


责任链模式的典型应用

(1)Java Servlet 过滤器链

在 Java 的 Servlet 技术中,过滤器链就是责任链模式的典型应用。多个过滤器可以按顺序处理一个请求,最终请求到达目标 Servlet 或 JSP。

(2)权限校验系统

在用户权限校验系统中,责任链模式可以用于不同级别的权限校验。每个处理者负责校验某一层级的权限,不通过时传递给下一个处理者。


责任链模式实现案例

中国古代对妇女制定了“三从四德”的道德规范,“三从”是指“未嫁从父、既嫁从夫、夫死从子”,也就是说一个女性,在没有结婚的时候要听从于父亲,结了婚后听从于丈夫,丈夫死了还要听儿子的。

举个例子来说,一个女的要出去逛街,同样这样的一个请求,在她没有出嫁前她必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?一般都是男的比女的死的早,还要问问儿子是否允许自己出去逛街,估计你下边马上要问要是没有儿子怎么办?请示小叔子、侄子等等,在父系社会中,妇女只占从属地位,现在想想中国的妇女还是比较悲惨的,逛个街还要请示来请示去,而且作为父亲、丈夫、儿子只有两种选择:要不承担起责任来告诉她允许或不允许逛街,要不就让她请示下一个人,这是整个社会体系的约束,应用到我们项目中就是业务规则,那我们来看怎么把“三从”通过我们的程序来实现,需求很简单:通过程序描述一下古代妇女的“三从”制度。

先看类图:

在这里插入图片描述

1、定义一个女性接口

package com.uhhe.common.design.chain;

/**
 * 古代悲哀女性的总称
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/3/2 9:55
 */
public interface IWomen {

    /**
     * 获得个人状况
     *
     * 1---未出嫁
     * 2---出嫁
     * 3---夫死
     *
     * @return 级别
     */
    int getType();

    /**
     * 获得个人请示,你要干什么?出去逛街?约会?还是看电影
     *
     * @return 请示内容
     */
    String getRequest();

}

2、女性实现类

package com.uhhe.common.design.chain;

/**
 * 女性实现类
 * 
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/3/2 10:02
 */
public class Women implements IWomen {

    private int type = 0;
    private String request;

    public Women(int type, String request) {
        this.type = type;
        // 为了显示好看点,在这里做了点处理
        switch (this.type) {
            case 1:
                this.request = "女儿的请求是:" + request;
                break;
            case 2:
                this.request = "妻子的请求是:" + request;
                break;
            case 3:
                this.request = "母亲的请求是:" + request;
            default:
                break;
        }
    }

    @Override
    public int getType() {
        return this.type;
    }

    @Override
    public String getRequest() {
        return this.request;
    }

}

3、定义有处理权的人员抽象类

package com.uhhe.common.design.chain;

/**
 * 父系社会,那就是男性有至高权利,handler控制权
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/3/2 9:54
 */
public abstract class Handler {

    /**
     * 能处理的级别
     */
    private int level;

    /**
     * 责任传递,下一个人责任人是谁
     */
    private Handler nextHandler;

    public Handler(int level) {
        // 每个类都要说明一下自己能处理哪些请求
        this.level = level;
    }

    /**
     * 一个女性(女儿,妻子或者是母亲)要求逛街,你要处理这个请求
     *
     * @param women 女人
     */
    public final void handlerMessage(IWomen women) {
        if (women.getType() == this.level) {
            this.response(women);
        } else {
            if (this.nextHandler != null) {
                // 有后续环节,才把请求往后递送
                this.nextHandler.handlerMessage(women);
            } else {
                // 已经没有后续处理人了,不用处理了
                System.out.println("-----------没地方请示了,不做处理!---------\n");
            }
        }
    }

    /**
     * 如果你属于你处理的返回,你应该让她找下一个环节的人
     * 比如: 女儿出嫁了,还向父亲请示是否可以逛街,那父亲就应该告诉女儿,应该找丈夫请示
     */
    public void setNext(Handler handler) {
        this.nextHandler = handler;
    }

    /**
     * 有请示那当然要回应
     *
     * @param women 女人
     */
    public abstract void response(IWomen women);

}

4、有权处理的三个实现类(父亲、丈夫、儿子)

package com.uhhe.common.design.chain;

/**
 * 父亲类
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/3/2 9:58
 */
public class Father extends Handler {

    public Father() {
        // 父亲只能处理请求类型为1的请求
        super(1);
    }

    @Override
    public void response(IWomen women) {
        System.out.println("--------女儿向父亲请示-------");
        System.out.println("类型:" + women.getType() + "\t" + women.getRequest());
        System.out.println("父亲的答复是: 同意\n");
    }

}
package com.uhhe.common.design.chain;

/**
 * 丈夫类
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/3/2 9:59
 */
public class Husband extends Handler {

    public Husband() {
        // 丈夫只能处理请求类型为2的请求
        super(2);
    }

    @Override
    public void response(IWomen women) {
        System.out.println("--------妻子向丈夫请示-------");
        System.out.println("类型:" + women.getType() + "\t" + women.getRequest());
        System.out.println("丈夫的答复是:同意\n");
    }

}
package com.uhhe.common.design.chain;

/**
 * 儿子类
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/3/2 10:00
 */
public class Son extends Handler {

    public Son() {
        // 儿子只能处理请求类型为 3
        super(3);
    }

    @Override
    public void response(IWomen women) {
        System.out.println("--------母亲向儿子请示-------");
        System.out.println("类型:" + women.getType() + "\t" + women.getRequest());
        System.out.println("儿子的答复是:同意\n");
    }

}

这三个类都很简单,构造方法是必须实现的,通过构造方法我们设置了各个类能处理的请求类型,Father 只能处理请求类型为 1(也就是女儿)的请求;Husband只能处理请求类型类 2(也就是妻子)的请求;儿子只能处理请求类型为 3(也就是目前)的请求。

5、去请求逛街

package com.uhhe.common.design.chain;

import java.util.ArrayList;
import java.util.Random;

/**
 * 后人来看这样的社会道德
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/3/2 10:05
 */
@SuppressWarnings("all")
public class Client {

    /**
     * 责任链模式【Chain of Responsibility Pattern】
     * <p>
     * 责任链模式屏蔽了请求的处理过程,你发起一个请求到底是谁处理的,这个你不用关心,只要你把请求抛给责任链的第一个处理者,
     * 最终会返回一个处理结果(当然也可以不做任何处理),作为请求者可以不用知道到底是需要谁来处理的,这是责任链模式的核心。
     * <p>
     * 责任链有一个缺点:调试不是很方便,特别是链条比较长,环节比较多的时候,由于采用了类似递归的方式,调试的时候逻辑可能比较复杂。
     * <p>
     * 同时责任链模式也可以做为一种补救模式来使用,举个简单例子,如项目开发的时候,需求确认是这样的:
     * 一个请求(比如银行客户存款的币种),一个处理者(只处理人民币),但是随着业务的发展(改革开放了嘛,还要处理美元、日元等等),
     * 处理者的数量和类型都有所增加,那这时候就可以在第一个处理者后面建立一个链,也就是责任链来处理请求,
     * 你是人民币,好,还是第一个业务逻辑来处理,
     * 你是美元,好,传递到第二个业务逻辑来处理,
     * 日元,欧元…,
     * 这些都不用在对原有的业务逻辑产生很大改变,通过扩展实现类就可以很好的解决这些需求变更的问题。
     */
    public static void main(String[] args) {
        // 随机挑选几个女性
        Random rand = new Random();
        ArrayList<IWomen> arrayList = new ArrayList();
        for (int i = 0; i < 5; i++) {
            arrayList.add(new Women(rand.nextInt(4), "我要出去逛街"));
        }

        // 定义三个请示对象
        Handler father = new Father();
        Handler husband = new Husband();
        Handler son = new Son();
        // 设置请示顺序
        father.setNext(husband);
        husband.setNext(son);

        for (IWomen women : arrayList) {
            father.handlerMessage(women);
        }
    }

}

总结:
责任链模式通过将请求的发送者与接收者解耦,使得多个对象有机会处理请求,增强了系统的灵活性和扩展性。在需要处理请求的职责动态分配、审批系统、事件处理等场景中,责任链模式是一种非常有效的设计模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值