责任链模式的设计与实现

责任链是什么

  1. 解耦请求发送者和接收者:发送者无需知道请求被哪个处理器处理
  2. 动态组合处理器:可以灵活的动态改变链的结构
  3. 请求沿链传递:请求可以由链中的一个或多个处理器处理

一般用在什么场景

  1. 请求需要多个处理器:日志记录的不同级别处理
  2. 动态指定处理流程:请求的处理方式不固定,依赖于运行时的链条结构
  3. 清除条件分支:责任链代替if else或者switch语句

责任链模式的组成

  1. 处理器接口(Handler):定义处理请求的通用方法和设置下一个处理器的方法
  2. 具体处理器(Concrete Handler):实现处理器接口,处理请求或传递给下一个处理器

实现

/**
* 责任链请求对象:封装审批所需的上下文数据
* 说明:用于在处理器链中传递与共享数据
* @author Jaymr
*/
@Getter
@AllArgsConstructor
public class ApprovalRequest {
private final String applicant; // 申请人
private final String purpose; // 申请用途
private final long amount; // 金额(单位:分)
}

/**
* 责任链的处理结果对象:描述处理状态与消息
* 说明:统一返回格式,方便上层判断是否中断链或继续传递
* @author Jaymr
*/
class ApprovalResult {
private final boolean handled; // 是否已处理并中断链
private final String message; // 处理信息

/**
* 构造函数:初始化处理结果
* @param handled 是否已处理并中断链(true 表示链到此结束)
* @param message 处理信息或原因描述
*/
public ApprovalResult(boolean handled, String message) {
this.handled = handled;
this.message = message;
}

/**
* 是否已处理并中断链
* @return true 表示链到此结束;false 表示继续传递
*/
public boolean isHandled() {
return handled;
}

/**
* 获取处理信息
* @return 信息描述
*/
public String getMessage() {
return message;
}

/**
* 创建“继续传递”的结果(未处理当前请求)
* @param info 说明信息
* @return ApprovalResult
*/
public static ApprovalResult pass(String info) {
return new ApprovalResult(false, info);
}

/**
* 创建“已处理并中断链”的结果
* @param info 说明信息
* @return ApprovalResult
*/
public static ApprovalResult stop(String info) {
return new ApprovalResult(true, info);
}
}

/**
* 责任链处理器接口
* 说明:定义统一的处理行为与链式传递约定
* @author Jaymr
*/
interface ApprovalHandler {
/**
* 设置下一个处理器
* @param next 下一个处理器实例
*/
void setNext(ApprovalHandler next);

/**
* 处理审批请求
* 约定:返回 handled=true 则中断链;handled=false 则由调用方继续传递给 next
* @param request 审批请求
* @return 处理结果:是否中断链与消息
*/
ApprovalResult handle(ApprovalRequest request);
}

/**
* 基础抽象处理器:封装“向下传递”的通用逻辑
* 说明:具体处理器继承该类,只需实现自己的处理判断与信息输出
* @author Jaymr
*/
abstract class AbstractApprovalHandler implements ApprovalHandler {
protected ApprovalHandler next;

/**
* 设置下一个处理器
* @param next 下一个处理器
*/
@Override
public void setNext(ApprovalHandler next) {
this.next = next;
}

/**
* 模板方法:子类实现 doHandle;若返回 handled=false 则继续传递
* @param request 审批请求
* @return 处理结果:可能中断或继续
*/
@Override
public ApprovalResult handle(ApprovalRequest request) {
ApprovalResult result = doHandle(request);
if (result.isHandled()) {
return result; // 中断链
}
// 未处理则继续传递给下一个处理器
if (next != null) {
return next.handle(request);
}
// 链尾仍未处理,返回默认结果
return ApprovalResult.stop("无人处理:审批请求未被任何角色接管");
}

/**
* 子类具体处理逻辑
* 实现者可决定是否处理并中断;或不处理让链继续
* @param request 审批请求
* @return 处理结果
*/
protected abstract ApprovalResult doHandle(ApprovalRequest request);
}

/**
* 组长审批处理器:可审批 <= 1000 元(分:100000)
* 说明:金额在 1000 元以内由组长审批并中断链,否则传递给下一个处理器
* @author Jaymr
*/
class TeamLeadHandler extends AbstractApprovalHandler {
private static final long LIMIT = 1000 * 100L;

/**
* 执行组长的审批逻辑
* @param request 审批请求
* @return 若金额<=1000元,则处理并中断链;否则不处理交给下一个
*/
@Override
protected ApprovalResult doHandle(ApprovalRequest request) {
if (request.getAmount() <= LIMIT) {
return ApprovalResult.stop("组长已审批通过(≤1000元):申请人=" + request.getApplicant());
}
return ApprovalResult.pass("组长权限不足,传递给上级");
}
}

/**
* 经理审批处理器:可审批 <= 10000 元(分:1000000)
* 说明:金额在 1 万以内由经理审批并中断链,否则传递给下一个处理器
* @author Jaymr
*/
class ManagerHandler extends AbstractApprovalHandler {
private static final long LIMIT = 10000 * 100L;

/**
* 执行经理的审批逻辑
* @param request 审批请求
* @return 若金额≤1万元,处理并中断链;否则传递
*/
@Override
protected ApprovalResult doHandle(ApprovalRequest request) {
if (request.getAmount() <= LIMIT) {
return ApprovalResult.stop("经理已审批通过(≤1万元):用途=" + request.getPurpose());
}
return ApprovalResult.pass("经理权限不足,传递给上级");
}
}

/**
* 总监审批处理器:可审批任意金额(示例)
* 说明:作为链尾处理器,若到达则一定处理并中断链
* @author Jaymr
*/
class DirectorHandler extends AbstractApprovalHandler {
/**
* 执行总监的审批逻辑
* @param request 审批请求
* @return 总监直接审批通过并中断链
*/
@Override
protected ApprovalResult doHandle(ApprovalRequest request) {
return ApprovalResult.stop("总监已审批通过(链尾兜底):金额=" + (request.getAmount() / 100.0) + "元");
}
}

/**
* 责任链构建器:简化链的拼装
* 说明:提供便捷方法构建标准审批链或自定义链顺序
* @author Jaymr
*/
class ApprovalChainBuilder {
/**
* 构建“组长 -> 经理 -> 总监”的标准审批链
* @return 链入口处理器(组长)
*/
public static ApprovalHandler standardChain() {
ApprovalHandler teamLead = new TeamLeadHandler();
ApprovalHandler manager = new ManagerHandler();
ApprovalHandler director = new DirectorHandler();
teamLead.setNext(manager);
manager.setNext(director);
return teamLead;
}

/**
* 自定义拼装:传入顺序构建为链
* @param handlers 按顺序提供处理器
* ApprovalHandler... handlers 等价于 ApprovalHandler[] handlers
* @return 链入口处理器(第一个)
*/
public static ApprovalHandler chainOf(ApprovalHandler... handlers) {
if (handlers == null || handlers.length == 0) {
throw new IllegalArgumentException("handlers 不能为空");
}
for (int i = 0; i < handlers.length - 1; i++) {
handlers[i].setNext(handlers[i + 1]);
}
return handlers[0];
}
}

/**
* 演示:使用责任链处理不同金额的审批请求
* 说明:展示链式中断与继续传递的效果
* @author Jaymr
*/
public class ChainDemo {
/**
* 主函数:构建链并执行示例请求
* @param args 命令行参数
*/
public static void main(String[] args) {
ApprovalHandler chain = ApprovalChainBuilder.standardChain();

ApprovalRequest r1 = new ApprovalRequest("Alice", "购买开发工具", 500 * 100L);
ApprovalRequest r2 = new ApprovalRequest("Bob", "团队团建", 5000 * 100L);
ApprovalRequest r3 = new ApprovalRequest("Carol", "大型设备采购", 120000 * 100L);

System.out.println(chain.handle(r1).getMessage()); // 组长处理并中断
System.out.println(chain.handle(r2).getMessage()); // 经理处理并中断
System.out.println(chain.handle(r3).getMessage()); // 总监兜底处理
}

/**
* 演示调用可变参数方法的不同写法
* @param lead 组长处理器
* @param manager 经理处理器
* @param director 总监处理器
*/
public static void demoCalls(ApprovalHandler lead, ApprovalHandler manager, ApprovalHandler director) {
// 直接传多个参数(编译器打包为数组)
ApprovalHandler chain1 = chainOf(lead, manager, director);

// 手动传数组(效果等同)
ApprovalHandler chain2 = chainOf(new ApprovalHandler[]{lead, manager, director});

// 传单个参数
ApprovalHandler chain3 = chainOf(lead);

// 传 0 个参数(将触发 IllegalArgumentException)
// ApprovalHandler chainEmpty = chainOf(); // 不建议:会抛异常

// 传 null(两种不同语义)
// chainOf((ApprovalHandler) null); // handlers.length == 1,元素是 null -> 会在拼接时抛异常
// chainOf((ApprovalHandler[]) null); // handlers 本身就是 null -> 会在校验处抛异常
}
}