20、设计模式之责任链模式(Chain)

一、什么是责任链模式

责任链模式属于行为型模式,在这个模式中,通常使用一条链来处理请求,该请求沿着链的顺序传递,直到有对象处理该请求为止,从而达到解耦请求发送者和请求处理者的目的。

二、组成

抽象处理器(Handler):定义处理请求的接口,提供一个抽象方法用于处理请求,并定义一个指向后继处理器的引用。

具体处理器(ConcreteHandler):实现抽象处理器接口,用于处理请求。如果当前处理器不能处理请求,则将请求传递给后继处理器。

三、优缺点

优点:

降低耦合度:请求发送者和接收者都没有对方的明确信息,而是通过抽象处理器来链接。实现了请求的发送者和处理者之间的解耦。

灵活性:可以动态地增加或删除处理器,方便扩展和维护。

易于实现: 在责任链模式中,每个具体的处理器只需要实现自己的功能即可,不需要知道整个请求链的存在,这样更加容易实现其功能。

缺点:

不能保证请求一定会被处理:在责任链模式中,由于请求的处理是由多个对象负责的,所以不能保证请求一定会被处理,存在漏洞导致请求无响应的风险。

性能问题:在应用责任链模式时需要控制链中的处理器数量,过多的处理器会导致处理时间增加,从而影响系统性能。

调试困难:责任链模式中的处理器是动态组合的,处理逻辑较为复杂,因此需要进行详细的测试和调试。

四、应用场景

4.1 应用实例

请假申请流程:公司内部的请假申请一般需要经过多级审批,每个审批者的职责不同,可以通过责任链模式实现申请者与处理者之间的解耦,让申请者的请求依次经过各个处理者的处理,直到最终得到审批结果。

商品退换货:在线商场中,如果用户需要对商品进行退换货,涉及到订单创建、退货申请、快递配送等诸多步骤,这些步骤可以通过责任链模式实现,让每个处理者负责自己的任务,将责任链串接起来,以便完成整个退换货流程。

请求处理中心:当一个请求需要经过多个处理节点进行处理时,可以采用责任链模式来组织这些处理节点,使得请求在节点之间循环传递,直到得到最终结果。例如,大型网站的访问请求处理中心,就可以采用责任链模式来处理请求。

系统安全中心:当系统发生安全威胁时,可以采用责任链模式来组织安全相关的处理节点,对异常数据进行检测和拦截,保障系统安全稳定运行。

4.2 程序场景

请求的处理顺序不确定:如果一个系统中存在多个处理请求的对象,且请求的处理可能需要先后顺序,则可以采用责任链模式,让不同的处理对象构成责任链,依次对请求进行处理。

有多个对象可以处理请求:如果一个请求可能需要由多个对象来进行处理,而这些处理对象之间相互独立,不需要知道其他处理对象的存在,则可以采用责任链模式来实现请求的处理。

需要动态安排处理流程:如果处理流程需要动态安排,可以通过动态组合责任链节点来实现。即根据实际需求,动态安排责任链的执行顺序和强度。

需要在不影响代码整体结构的情况下,进行功能扩展:使用责任链模式可以方便地扩展系统的功能,对业务逻辑和系统结构的初始设计基本无影响,只需要添加新的处理节点、修改处理节点间的联系即可。

五、代码实现

下面以学校请假审批流程为例。我们假设有三个教师,分别是班主任、年级组长和校长。如果一位教师请假,需要经过这三个人的审批,但请假天数的不同就需要不同的审批者。

5.0 UML类图

5.1 Approver(审批者)

java 复制代码
/**
 * 
 * 审批者,包括班主任、年级组长和校长
 */
public abstract class Approver {
    String name;
    Approver next;
 
    public Approver(String name){
        this.name=name;
    }
 
    //设置下一个审批者
    public void setNext(Approver next){
        this.next=next;
    }
 
    //审批请求
    public abstract void approve(LeaveRequest request);
}

5.2 Master(校长)

java 复制代码
/**
 *
 * 校长 请假天数大于七天,年级组长和班主任都没权力审批,交给校长
 */
public class Master extends Approver{
 
    public Master(String name){
        super(name);
    }
 
    @Override
    public void approve(LeaveRequest request) {
        if (request.getDays() > 7) {
            System.out.println("校长" + name + "审批了" + request.getName() + "的请假申请,天数为" + request.getDays());
        } else {
            if (next != null) {
                next.approve(request);
            }
        }
    }
}

5.3 GradeLeader(年级组长)

java 复制代码
/**
 * 
 * 年级组长,请假天数2-7天,班主任处理不了,交给年级主任
 */
public class GradeLeader extends Approver {
 
    public GradeLeader(String name){
        super(name);
    }
 
    @Override
    public void approve(LeaveRequest request) {
        if (request.getDays() <= 7) {
            System.out.println("年级组长" + name + "审批" + request.getName() + "的请假申请,天数为" + request.getDays());
        } else {
            if (next != null) {
                System.out.println("年级组长审批不了,交由下一级");
                next.approve(request);
            }
        }
    }
}

5.4 ClassAdviser(班主任)

java 复制代码
/**
 * 
 * 班主任,请假天数2天内,班主任就可以审批
 */
public class ClassAdviser extends Approver{
 
    public ClassAdviser(String name){
        super(name);
    }
 
    @Override
    public void approve(LeaveRequest request) {
        if (request.getDays() <= 2) {
            System.out.println("班主任" + name + "审批" + request.getName() + "的请假申请,天数为" + request.getDays());
        } else {
            if (next != null) {
                System.out.println("班主任审批不了,交由下一级");
                next.approve(request);
            }
        }
    }
}

5.5 LeaveRequest(请假信息)

java 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;
/**
 * 
 * 请假信息
 */
@AllArgsConstructor
@Data
public class LeaveRequest {
    //请假人姓名
    private String name;
    //请假天数
    private Integer days;
}

5.6 TestChain

java 复制代码
/**
 * 
 * 责任链模式
 */
@SpringBootTest
public class TestChain {
    @Test
    void testChain(){
        Approver classAdviser = new ClassAdviser("张三");
        Approver gradeLeader = new GradeLeader("李四");
        Approver schoolMaster = new Master("王五");
 
        //组织责任链
        classAdviser.setNext(gradeLeader);
        gradeLeader.setNext(schoolMaster);
 
        //发起请求
        LeaveRequest request = new LeaveRequest("小明", 10);
        classAdviser.approve(request);
    }
}

5.7 总结

在这个例子中,每个审批者对应一个Approver对象,班主任、年级组长和校长分别继承自Approver类。每个Approver对象都有一个next属性,代表下一个审批者,这样就形成了一个责任链。在处理请求的时候,如果当前审批者可以处理请求,就处理请求;否则将请求传递给下一个审批者处理。

可以看到,在这个例子中,如果请假天数小于等于2天,班主任就处理请求;如果请假天数小于等于7天,年级组长就处理请求;如果请假天数大于7天,校长就处理请求。如果当前审批者无法处理请求,就将请求传递给下一个审批者处理,直到所有审批者都处理完成。

相关推荐
晨米酱8 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
数据智能老司机13 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机14 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机14 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机14 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
使一颗心免于哀伤14 小时前
《设计模式之禅》笔记摘录 - 21.状态模式
笔记·设计模式
数据智能老司机1 天前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
烛阴2 天前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
李广坤2 天前
工厂模式
设计模式