116、23种设计模式之责任链模式(23/23)(完结撒花)

一、责任链模式(Chain of Responsibility)定义

责任链模式是一种行为型设计模式 ,其核心思想是:将请求的发送者和接收者解耦,把多个处理对象连成一条链,请求沿着这条链传递,直到有一个对象处理该请求为止。

每个处理对象(处理器)都包含对下一个处理器的引用,当请求到达时,处理器先判断自己是否能处理该请求:

  • 若能处理,则直接处理,不再传递;
  • 若不能处理,则将请求转发给链中的下一个处理器。

官方定义:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

二、核心角色

(1)抽象处理者(Handler):定义处理请求的接口,包含抽象处理方法和一个指向后续处理器的引用。

(2)具体处理者(ConcreteHandler):实现抽象处理者的接口,判断是否能处理当前请求,若能则处理,否则转发给下一个处理器。

(3)客户端(Client):创建责任链,并将请求发送到链的第一个处理器。

三、应用场景

责任链模式适用于请求需要多个对象依次处理,且不确定哪个对象最终处理的场景,典型案例:

(1)请求审批流程:如请假审批(小组长→部门经理→总监→CEO),不同请假时长由不同层级审批;

(2)异常处理链:多层级的异常捕获与处理,上层处理器处理不了的异常交给下层;

(3)日志框架:不同级别日志(Debug→Info→Warn→Error)由不同的日志处理器处理;

(4)过滤器 / 拦截器:如 Web 框架中的请求拦截器(权限校验→参数校验→日志记录);

(5)事件分发:GUI 系统中的事件传递(如按钮点击事件沿组件树传递)。

四、优缺点

1、优点

(1)解耦请求发送者与接收者:发送者无需知道请求由谁处理,接收者无需知道请求的完整链路;

(2)灵活性高:可动态增删 / 调整处理器的顺序,符合 "开闭原则";

(3)单一职责:每个处理器只负责自己的处理逻辑,职责清晰;

(4)简化对象间交互:对象仅需持有下一个处理器的引用,无需维护所有处理器。

2、缺点

(1)性能风险:请求可能遍历整个链却无人处理,导致性能损耗;

(2)调试难度大:链的层级过多时,定位请求处理节点复杂;

(3)链的顺序依赖:若处理器顺序配置错误,可能导致请求处理异常;

(4)可能存在循环引用:若链的配置错误,可能出现请求无限循环传递。

五、C# 代码实例(请假审批场景)

1、场景说明

模拟公司请假审批流程:

  • 请假时长≤1 天:小组长审批;
  • 1 天 < 时长≤3 天:部门经理审批;
  • 3 天 < 时长≤7 天:总监审批;
  • 时长 > 7 天:CEO 审批;
  • 超出范围则拒绝。

2、代码实现

csharp 复制代码
using System;

// 1. 抽象处理者(审批者)
public abstract class Approver
{
    // 下一个审批者
    protected Approver NextApprover;
    // 审批者名称
    public string Name { get; }

    public Approver(string name)
    {
        Name = name;
    }

    // 设置下一个审批者
    public void SetNextApprover(Approver nextApprover)
    {
        NextApprover = nextApprover;
    }

    // 抽象审批方法
    public abstract void ApproveLeave(LeaveRequest request);
}

// 2. 具体处理者:小组长
public class GroupLeader : Approver
{
    public GroupLeader(string name) : base(name) { }

    public override void ApproveLeave(LeaveRequest request)
    {
        if (request.Days <= 1)
        {
            Console.WriteLine($"[{Name}] 审批通过:{request.EmployeeName} 请假 {request.Days} 天");
        }
        else if (NextApprover != null)
        {
            Console.WriteLine($"[{Name}] 无权限审批,转发给下一级");
            NextApprover.ApproveLeave(request);
        }
        else
        {
            Console.WriteLine($"[{Name}] 审批拒绝:无更高层级审批者");
        }
    }
}

// 具体处理者:部门经理
public class DepartmentManager : Approver
{
    public DepartmentManager(string name) : base(name) { }

    public override void ApproveLeave(LeaveRequest request)
    {
        if (request.Days > 1 && request.Days <= 3)
        {
            Console.WriteLine($"[{Name}] 审批通过:{request.EmployeeName} 请假 {request.Days} 天");
        }
        else if (NextApprover != null)
        {
            Console.WriteLine($"[{Name}] 无权限审批,转发给下一级");
            NextApprover.ApproveLeave(request);
        }
        else
        {
            Console.WriteLine($"[{Name}] 审批拒绝:无更高层级审批者");
        }
    }
}

// 具体处理者:总监
public class Director : Approver
{
    public Director(string name) : base(name) { }

    public override void ApproveLeave(LeaveRequest request)
    {
        if (request.Days > 3 && request.Days <= 7)
        {
            Console.WriteLine($"[{Name}] 审批通过:{request.EmployeeName} 请假 {request.Days} 天");
        }
        else if (NextApprover != null)
        {
            Console.WriteLine($"[{Name}] 无权限审批,转发给下一级");
            NextApprover.ApproveLeave(request);
        }
        else
        {
            Console.WriteLine($"[{Name}] 审批拒绝:无更高层级审批者");
        }
    }
}

// 具体处理者:CEO
public class CEO : Approver
{
    public CEO(string name) : base(name) { }

    public override void ApproveLeave(LeaveRequest request)
    {
        if (request.Days > 7 && request.Days <= 30)
        {
            Console.WriteLine($"[{Name}] 审批通过:{request.EmployeeName} 请假 {request.Days} 天");
        }
        else
        {
            Console.WriteLine($"[{Name}] 审批拒绝:{request.EmployeeName} 请假 {request.Days} 天(超出最大请假天数)");
        }
    }
}

// 请假请求实体
public class LeaveRequest
{
    // 员工姓名
    public string EmployeeName { get; set; }
    // 请假天数
    public int Days { get; set; }
}

// 3. 客户端调用
class Program
{
    static void Main(string[] args)
    {
        // 构建审批链:小组长 → 部门经理 → 总监 → CEO
        Approver groupLeader = new GroupLeader("小组长-张三");
        Approver deptManager = new DepartmentManager("部门经理-李四");
        Approver director = new Director("总监-王五");
        Approver ceo = new CEO("CEO-赵六");

        // 设置链的顺序
        groupLeader.SetNextApprover(deptManager);
        deptManager.SetNextApprover(director);
        director.SetNextApprover(ceo);

        // 测试不同请假天数的审批流程
        Console.WriteLine("=== 测试1:请假1天 ===");
        groupLeader.ApproveLeave(new LeaveRequest { EmployeeName = "小明", Days = 1 });

        Console.WriteLine("\n=== 测试2:请假2天 ===");
        groupLeader.ApproveLeave(new LeaveRequest { EmployeeName = "小红", Days = 2 });

        Console.WriteLine("\n=== 测试3:请假5天 ===");
        groupLeader.ApproveLeave(new LeaveRequest { EmployeeName = "小刚", Days = 5 });

        Console.WriteLine("\n=== 测试4:请假10天 ===");
        groupLeader.ApproveLeave(new LeaveRequest { EmployeeName = "小李", Days = 10 });

        Console.WriteLine("\n=== 测试5:请假31天(超出范围) ===");
        groupLeader.ApproveLeave(new LeaveRequest { EmployeeName = "小王", Days = 31 });
    }
}

3、输出结果

csharp 复制代码
=== 测试1:请假1天 ===
[小组长-张三] 审批通过:小明 请假 1 天

=== 测试2:请假2天 ===
[小组长-张三] 无权限审批,转发给下一级
[部门经理-李四] 审批通过:小红 请假 2 天

=== 测试3:请假5天 ===
[小组长-张三] 无权限审批,转发给下一级
[部门经理-李四] 无权限审批,转发给下一级
[总监-王五] 审批通过:小刚 请假 5 天

=== 测试4:请假10天 ===
[小组长-张三] 无权限审批,转发给下一级
[部门经理-李四] 无权限审批,转发给下一级
[总监-王五] 无权限审批,转发给下一级
[CEO-赵六] 审批通过:小李 请假 10 天

=== 测试5:请假31天(超出范围) ===
[小组长-张三] 无权限审批,转发给下一级
[部门经理-李四] 无权限审批,转发给下一级
[总监-王五] 无权限审批,转发给下一级
[CEO-赵六] 审批拒绝:小王 请假 31 天(超出最大请假天数)

六、总结

**1、核心价值:**责任链模式的核心是 "解耦",让请求的发送者和接收者完全隔离,符合 "迪米特法则";

**2、适用场景:**请求需要多节点处理、处理节点动态变化、无需明确知道处理者的场景;
3、使用建议:

  • 控制链的长度,避免过长导致性能问题;
  • 确保链的末端有默认处理逻辑(如拒绝请求),防止请求 "丢失";
  • 可通过配置文件动态构建链,提升灵活性;

4、与其他模式的区别:

  • 与装饰器模式:责任链是 "处理或转发",装饰器是 "增强功能并传递";
  • 与状态模式:责任链的处理逻辑由处理器决定,状态模式的处理逻辑由对象状态决定。

责任链模式在实际开发中应用广泛(如ASP.NET Core 的中间件、过滤器),合理使用可大幅提升代码的扩展性和可维护性,但需注意避免过度设计导致链层级冗余。

相关推荐
吃喝不愁霸王餐APP开发者12 小时前
利用责任链模式解耦多平台(美团/饿了么)霸王餐接口的适配逻辑
android·责任链模式
资生算法程序员_畅想家_剑魔15 小时前
Java常见技术分享-11-责任链模式
java·spring boot·责任链模式
程序员阿鹏16 小时前
责任链模式
java·spring·servlet·tomcat·maven·责任链模式
山沐与山19 小时前
【设计模式】Python模板方法模式:从入门到实战
python·设计模式·模板方法模式
阿拉斯攀登21 小时前
设计模式:责任链模式
设计模式·责任链模式
崎岖Qiu1 天前
【设计模式笔记18】:并发安全与双重检查锁定的单例模式
java·笔记·单例模式·设计模式
阿闽ooo1 天前
单例模式深度解析:从饿汉到懒汉的实战演进
开发语言·c++·笔记·设计模式
阿拉斯攀登1 天前
设计模式:责任链模式(Spring Security)
设计模式·spring security·责任链模式
阿拉斯攀登1 天前
设计模式:责任链模式(springmvc应用)
设计模式·springmvc·责任链模式