设计模式详解-责任链模式

设计模式详解:责任链模式

一、模式概述

责任链模式(Chain of Responsibility Pattern)是行为型设计模式中最具流程解耦价值的模式,其核心意图在于使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。这一模式将请求的处理者组织为链式结构,每个处理者决定是否处理请求或将其传递给下一个处理者。

责任链模式的命名源自其结构形态——"链"即前后衔接的处理者序列,"责任"即每个处理者承担的特定职责。在现实世界中,采购审批流程、技术支持升级、公文流转签批,均是责任链的生动隐喻:基层员工处理常规请求,超出权限则提交主管,主管再超出则提交总监,直至某一层级能够做出决策。

责任链模式的深层价值在于动态组合与灵活编排。与条件分支相比,责任链将判断逻辑分散到各个处理者中,新增处理者无需修改既有代码;与策略模式相比,责任链允许多个处理者协作处理同一请求,而非仅选择一个。在请求的处理路径不确定、处理者动态变化、需要逐步升级处理的场景中,责任链模式展现出独特的架构优势。

二、模式结构

责任链模式包含两个核心角色,形成松散的链式委托结构:

抽象处理者(Handler):定义一个处理请求的接口,通常包含setNext()方法设定后继者,以及handle()方法处理请求。可以定义一个默认实现,将请求转发给后继者。

具体处理者(Concrete Handler):实现抽象处理者的接口,处理它所负责的请求。如果它能够处理请求,则处理之;否则将请求转发给后继者。

客户端(Client):向链上的具体处理者对象提交请求。客户端可以组装链的结构,也可以从工厂获取预配置的链。

责任链的关键设计决策在于链的组装方式。可以静态配置(如Spring的依赖注入),可以动态构建(如运行时根据条件选择处理者),也可以基于规则引擎自动编排。

三、深度案例:企业级支付路由与风控决策引擎

以下展示一个真实场景下的责任链模式应用——金融支付平台的交易处理流水线,涵盖参数校验、风控检查、限额控制、渠道选择、费用计算、通知发送等多阶段处理,每个阶段由多个处理者竞争或协作完成。

3.1 问题域分析:嵌套条件分支的泥潭

java
// 反模式:巨型条件分支的交易处理 public class NaivePaymentService { public PaymentResult process(PaymentRequest request) { // 1. 参数校验 if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) { return PaymentResult.invalid("金额无效"); } if (request.getPayerAccount() == null || request.getPayerAccount().isEmpty()) { return PaymentResult.invalid("付款账户无效"); } // 更多校验... // 2. 风控检查 RiskLevel risk = riskService.assess(request); if (risk == RiskLevel.HIGH) { if (request.getAmount().compareTo(new BigDecimal("10000")) > 0) { return PaymentResult.blocked("高风险大额交易"); } // 发送增强验证 if (!verifyEnhanced(request)) { return PaymentResult.challenge("增强验证失败"); } } else if (risk == RiskLevel.MEDIUM) { if (request.getAmount().compareTo(new BigDecimal("50000")) > 0) { request.setNeedApproval(true); } } // 3. 限额检查 BigDecimal dailyLimit = limitService.getDailyLimit(request.getPayerAccount()); BigDecimal used = limitService.getDailyUsed(request.getPayerAccount()); if (used.add(request.getAmount()).compareTo(dailyLimit) > 0) { if (request.isSkipLimit()) { if (!hasSpecialPermission(request.getOperatorId())) { return PaymentResult.limitExceeded("无越限权限"); } } else { return PaymentResult.limitExceeded("超出日限额"); } } // 4. 渠道选择 PaymentChannel channel; if (request.getPreferredChannel() != null) { channel = request.getPreferredChannel(); } else { if (request.getAmount().compareTo(new BigDecimal("1000")) <= 0) { channel = selectLowCostChannel(); } else if (request.getCurrency().equals("USD")) { channel = selectSwiftChannel(); } else { channel = selectDefaultChannel(); } } // 5. 费用计算 BigDecimal fee; if (request.getFeeBearer() == FeeBearer.PAYER) { fee = calculatePayerFee(channel, request.getAmount()); } else { fee = calculatePayeeFee(channel, request.getAmount()); } // 6. 执行支付 // ... // 7. 通知 if (request.isNotifyPayer()) { notificationService.sendToPayer(request); } if (request.isNotifyPayee()) { notificationService.sendToPayee(request); } return PaymentResult.success(); } }

上述代码每新增一种处理规则,需修改核心服务,条件嵌套层层加深,测试覆盖难度指数级增长。责任链模式将此重构为可插拔的处理链。

3.2 抽象层:请求与处理者契约

java
/** * 抽象处理者:支付处理节点 * 支持同步/异步、中断/继续、前置/后置等高级特性 */ public abstract class PaymentHandler { // 后继处理者 private PaymentHandler next; // 处理者元数据 private final HandlerMetadata metadata; protected PaymentHandler(HandlerMetadata metadata) { this.metadata = metadata; } /** * 设置后继处理者(构建链) */ public PaymentHandler setNext(PaymentHandler next) { this.next = next; return next; // 支持链式构建 } /** * 模板方法:定义处理骨架 */ public final PaymentContext handle(PaymentContext context) { // 1. 前置处理(可选覆盖) if (!beforeHandle(context)) { return context; // 前置拦截 } // 2. 核心处理 HandleResult result = doHandle(context); // 3. 根据结果决策 switch (result.getDecision()) { case CONTINUE: // 继续传递 context = result.getUpdatedContext(); break; case TERMINATE: // 终止链,返回结果 return result.getUpdatedContext(); case RETRY: // 重试当前处理者 return handle(context.retry()); case SKIP_NEXT: // 跳过若干后续处理者 PaymentHandler skipTarget = findSkipTarget(result.getSkipCount()); if (skipTarget != null) { return skipTarget.handle(result.getUpdatedContext()); } return result.getUpdatedContext(); } // 4. 后置处理(可选覆盖) context = afterHandle(context); // 5. 传递给后继 if (next != null) { return next.handle(context); } return context; } /** * 核心处理逻辑:子类必须实现 */ protected abstract HandleResult doHandle(PaymentContext context); /** * 前置钩子 */ protected boolean beforeHandle(PaymentContext context) { return true; // 默认通过 } /** * 后置钩子 */ protected PaymentContext afterHandle(PaymentContext context) { return context; // 默认无操作 } /** * 判断是否支持处理该请求 */ public abstract boolean supports(PaymentContext context); /** * 获取处理者优先级(数值越小越优先) */ public int getPriority() { return metadata.getPriority(); } private PaymentHandler findSkipTarget(int skipCount) { PaymentHandler current = this; for (int i = 0; i < skipCount && current != null; i++) { current = current.next; } return current; } } /** * 处理结果:包含决策与更新后的上下文 */ public class HandleResult { public enum Decision { CONTINUE, // 继续后续处理 TERMINATE, // 终止链 RETRY, // 重试当前 SKIP_NEXT // 跳过N个后续处理者 } private final Decision decision; private final PaymentContext updatedContext; private final int skipCount; // SKIP_NEXT时有效 // Builder模式构建 } /** * 支付上下文:贯穿整个处理链的共享状态 */ public class PaymentContext { private final PaymentRequest originalRequest; private PaymentStatus currentStatus; private List<ValidationError> validationErrors; private RiskAssessment riskAssessment; private PaymentChannel selectedChannel; private BigDecimal calculatedFee; private List<ProcessingStep> processingSteps; private Map<String, Object> attributes; // 不可变请求,可变处理状态 public PaymentContext(PaymentRequest request) { this.originalRequest = request; this.currentStatus = PaymentStatus.INITIATED; this.processingSteps = new ArrayList<>(); this.attributes = new HashMap<>(); } // 状态更新方法... public PaymentContext withStatus(PaymentStatus status) { this.currentStatus = status; return this; } public PaymentContext addStep(ProcessingStep step) { this.processingSteps.add(step); return this; } public PaymentContext setAttribute(String key, Object value) { this.attributes.put(key, value); return this; } public PaymentContext retry() { // 重置部分状态,准备重试 return this; } }

3.3 具体处理者:专业化处理节点

java
/** * 具体处理者:参数校验 * 链首节点,快速失败 */ @Component public class ParameterValidationHandler extends PaymentHandler { private final List<FieldValidator> validators; @Autowired public ParameterValidationHandler(List<FieldValidator> validators) { super(HandlerMetadata.builder() .id("param-validation") .priority(10) .description("请求参数校验") .build()); this.validators = validators; } @Override public boolean supports(PaymentContext context) { return true; // 所有请求都需要校验 } @Override protected HandleResult doHandle(PaymentContext context) { PaymentRequest request = context.getOriginalRequest(); List<ValidationError> errors = new ArrayList<>(); for (FieldValidator validator : validators) { Optional<ValidationError> error = validator.validate(request); error.ifPresent(errors::add); } if (!errors.isEmpty()) { return HandleResult.terminate( context.withStatus(PaymentStatus.VALIDATION_FAILED) .setAttribute("validationErrors", errors) ); } return HandleResult.continueWith( context.withStatus(PaymentStatus.VALIDATED) .addStep(ProcessingStep.validationSuccess()) ); } } /** * 具体处理者:风控评估 * 根据风险等级决定后续路径 */ @Component public class RiskAssessmentHandler extends PaymentHandler { private final RiskEngine riskEngine; private final EnhancedVerificationService verificationService; @Autowired public RiskAssessmentHandler(RiskEngine riskEngine, EnhancedVerificationService verificationService) { super(HandlerMetadata.builder() .id("risk-assessment") .priority(20) .description("实时风险评估") .build()); this.riskEngine = riskEngine; this.verificationService = verificationService; } @Override public boolean supports(PaymentContext context) { // 仅对特定金额以上的交易进行风控 return context.getOriginalRequest().getAmount() .compareTo(new BigDecimal("100")) >= 0; } @Override protected HandleResult doHandle(PaymentContext context) { PaymentRequest request = context.getOriginalRequest(); RiskAssessment assessment = riskEngine.assess(request); context = context.setAttribute("riskAssessment", assessment); switch (assessment.getLevel()) { case LOW: return HandleResult.continueWith( context.withStatus(PaymentStatus.RISK_CLEARED) ); case MEDIUM: // 中等风险:标记需审批,继续 return HandleResult.continueWith( context.withStatus(PaymentStatus.PENDING_APPROVAL) .setAttribute("approvalRequired", true) .setAttribute("approvalLevel", assessment.getSuggestedApprovalLevel()) ); case HIGH: // 高风险:检查是否已通过增强验证 if (context.getOriginalRequest().getEnhancedToken() != null) { boolean verified = verificationService.verify( request.getPayerAccount(), request.getEnhancedToken() ); if (verified) { return HandleResult.continueWith( context.withStatus(PaymentStatus.ENHANCED_VERIFIED) ); } } // 未通过增强验证:终止并挑战 return HandleResult.terminate( context.withStatus(PaymentStatus.CHALLENGE_REQUIRED) .setAttribute("challengeMethod", ChallengeMethod.SMS_OTP) .setAttribute("challengeTarget", request.getPayerMobile()) ); case CRITICAL: // 极高风险:直接阻断 return HandleResult.terminate( context.withStatus(PaymentStatus.BLOCKED) .setAttribute("blockReason", assessment.getBlockReason()) .setAttribute("blockCode", assessment.getBlockCode()) ); default: throw new IllegalStateException("未知风险等级"); } } } /** * 具体处理者:限额控制 * 支持多级限额:单笔、日累计、月累计 */ @Component public class LimitControlHandler extends PaymentHandler { private final LimitService limitService; private final OverrideService overrideService; @Override protected HandleResult doHandle(PaymentContext context) { PaymentRequest request = context.getOriginalRequest(); String accountNo = request.getPayerAccount(); BigDecimal amount = request.getAmount(); // 检查多级限额 List<LimitCheck> checks = Arrays.asList( new LimitCheck(LimitType.PER_TRANSACTION, amount, limitService.getTransactionLimit(accountNo)), new LimitCheck(LimitType.DAILY_CUMULATIVE, limitService.getDailyUsed(accountNo).add(amount), limitService.getDailyLimit(accountNo)), new LimitCheck(LimitType.MONTHLY_CUMULATIVE, limitService.getMonthlyUsed(accountNo).add(amount), limitService.getMonthlyLimit(accountNo)) ); List<LimitViolation> violations = new ArrayList<>(); for (LimitCheck check : checks) { if (check.isExceeded()) { violations.add(new LimitViolation(check.getType(), check.getLimit(), check.getActual())); } } if (violations.isEmpty()) { return HandleResult.continueWith( context.withStatus(PaymentStatus.LIMIT_CLEARED) ); } // 存在越限:检查是否有特殊权限覆盖 if (request.getOverrideToken() != null) { OverrideResult override = overrideService.validate( request.getOverrideToken(), violations, request.getOperatorId() ); if (override.isApproved()) { return HandleResult.continueWith( context.withStatus(PaymentStatus.LIMIT_OVERRIDDEN) .setAttribute("overrideApprover", override.getApprover()) .setAttribute("overrideReason", override.getReason()) ); } } // 无覆盖权限:终止 return HandleResult.terminate( context.withStatus(PaymentStatus.LIMIT_EXCEEDED) .setAttribute("limitViolations", violations) ); } } /** * 具体处理者:智能渠道路由 * 根据交易特征选择最优支付渠道 */ @Component public class ChannelRoutingHandler extends PaymentHandler { private final ChannelScorer channelScorer; private final ChannelHealthMonitor healthMonitor; @Override protected HandleResult doHandle(PaymentContext context) { PaymentRequest request = context.getOriginalRequest(); // 获取候选渠道 List<PaymentChannel> candidates = getCandidateChannels(request); // 评分排序 List<ChannelScore> scored = candidates.stream() .filter(c -> healthMonitor.isHealthy(c.getCode())) .map(c -> new ChannelScore(c, channelScorer.score(c, request))) .sorted(Comparator.comparing(ChannelScore::getScore).reversed()) .collect(Collectors.toList()); if (scored.isEmpty()) { return HandleResult.terminate( context.withStatus(PaymentStatus.NO_AVAILABLE_CHANNEL) ); } // 选择最优渠道 PaymentChannel selected = scored.get(0).getChannel(); // 设置渠道特定参数 context = context.setAttribute("selectedChannel", selected) .setAttribute("channelScores", scored) .setAttribute("channelRouteReason", generateRouteReason(selected, scored)); // 如果首选渠道不可用,标记降级 if (request.getPreferredChannel() != null && !selected.getCode().equals(request.getPreferredChannel())) { context = context.setAttribute("channelDegraded", true); } return HandleResult.continueWith( context.withStatus(PaymentStatus.CHANNEL_SELECTED) ); } private List<PaymentChannel> getCandidateChannels(PaymentRequest request) { List<PaymentChannel> candidates = new ArrayList<>(); // 用户首选 if (request.getPreferredChannel() != null) { candidates.add(channelRepository.findByCode(request.getPreferredChannel())); } // 根据币种、金额、时效要求匹配 candidates.addAll(channelRepository.findByCriteria( ChannelCriteria.builder() .currency(request.getCurrency()) .minAmount(request.getAmount()) .maxAmount(request.getAmount()) .requiredCompletionTime(request.getRequiredCompletionTime()) .build() )); // 兜底渠道 candidates.add(channelRepository.getDefaultChannel()); return candidates.stream().distinct().collect(Collectors.toList()); } } /** * 具体处理者:费用计算 */ @Component public class FeeCalculationHandler extends PaymentHandler { private final FeeRuleEngine feeEngine; @Override protected HandleResult doHandle(PaymentContext context) { PaymentRequest request = context.getOriginalRequest(); PaymentChannel channel = context.getAttribute("selectedChannel"); FeeCalculation fee = feeEngine.calculate(FeeRequest.builder() .amount(request.getAmount()) .currency(request.getCurrency()) .channel(channel) .feeBearer(request.getFeeBearer()) .payerType(request.getPayerType()) .payeeType(request.getPayeeType()) .urgency(request.getUrgency()) .build()); return HandleResult.continueWith( context.withStatus(PaymentStatus.FEE_CALCULATED) .setAttribute("calculatedFee", fee) .setAttribute("totalDeduction", request.getAmount().add(fee.getTotalFee())) ); } } /** * 具体处理者:交易执行 */ @Component public class TransactionExecutionHandler extends PaymentHandler { private final TransactionExecutor executor; private final IdempotencyGuard idempotencyGuard; @Override protected HandleResult doHandle(PaymentContext context) { // 幂等检查 if (!idempotencyGuard.acquire(context.getOriginalRequest().getIdempotencyKey())) { return HandleResult.terminate( context.withStatus(PaymentStatus.DUPLICATE_REQUEST) ); } PaymentChannel channel = context.getAttribute("selectedChannel"); BigDecimal totalDeduction = context.getAttribute("totalDeduction"); ExecutionResult result = executor.execute(ExecutionRequest.builder() .channel(channel) .payerAccount(context.getOriginalRequest().getPayerAccount()) .payeeAccount(context.getOriginalRequest().getPayeeAccount()) .amount(context.getOriginalRequest().getAmount()) .fee(context.getAttribute("calculatedFee")) .totalDeduction(totalDeduction) .build()); if (result.isSuccess()) { return HandleResult.continueWith( context.withStatus(PaymentStatus.EXECUTED) .setAttribute("transactionId", result.getTransactionId()) .setAttribute("executionTime", result.getExecutionTime()) .setAttribute("channelReference", result.getChannelReference()) ); } else { return HandleResult.terminate( context.withStatus(PaymentStatus.EXECUTION_FAILED) .setAttribute("executionError", result.getErrorCode()) .setAttribute("executionErrorMessage", result.getErrorMessage()) .setAttribute("retryable", result.isRetryable()) ); } } } /** * 具体处理者:后置通知 * 链尾节点,确保通知发送 */ @Component public class NotificationHandler extends PaymentHandler { private final NotificationDispatcher dispatcher; @Override public boolean supports(PaymentContext context) { // 仅对成功执行的交易发送通知 return context.getCurrentStatus() == PaymentStatus.EXECUTED; } @Override protected HandleResult doHandle(PaymentContext context) { PaymentRequest request = context.getOriginalRequest(); List<NotificationTask> tasks = new ArrayList<>(); if (request.isNotifyPayer()) { tasks.add(NotificationTask.builder() .recipient(request.getPayerNotificationAddress()) .template("payment_success_payer") .variables(buildPayerVariables(context)) .build()); } if (request.isNotifyPayee()) { tasks.add(NotificationTask.builder() .recipient(request.getPayeeNotificationAddress()) .template("payment_success_payee") .variables(buildPayeeVariables(context)) .build()); } // 异步发送,不阻塞 dispatcher.dispatchAsync(tasks); return HandleResult.continueWith( context.withStatus(PaymentStatus.NOTIFICATION_QUEUED) ); } }

3.4 链的装配与管理

java
/** * 链工厂:动态构建处理链 */ @Component public class PaymentChainFactory { private final List<PaymentHandler> allHandlers; private final HandlerRegistry registry; @Autowired public PaymentChainFactory(List<PaymentHandler> handlers, HandlerRegistry registry) { this.allHandlers = handlers.stream() .sorted(Comparator.comparingInt(PaymentHandler::getPriority)) .collect(Collectors.toList()); this.registry = registry; } /** * 构建标准处理链 */ public PaymentHandler buildStandardChain() { PaymentHandler head = new HeadHandler(); PaymentHandler current = head; for (PaymentHandler handler : allHandlers) { if (handler.supportsStandardFlow()) { current = current.setNext(handler); } } return head; } /** * 构建快速通道链(跳过部分检查) */ public PaymentHandler buildFastTrackChain() { PaymentHandler head = new HeadHandler(); PaymentHandler current = head; for (PaymentHandler handler : allHandlers) { if (handler.supportsFastTrack()) { current = current.setNext(handler); } } return head; } /** * 构建定制化链(基于交易特征) */ public PaymentHandler buildCustomChain(PaymentRequest request) { PaymentHandler head = new HeadHandler(); PaymentHandler current = head; // 根据请求特征选择处理者 List<PaymentHandler> selected = selectHandlers(request); for (PaymentHandler handler : selected) { current = current.setNext(handler); } return head; } /** * 基于规则的动态链编排 */ public PaymentHandler buildRuleBasedChain(PaymentRequest request) { List<HandlerRule> rules = registry.findRules(request); PaymentHandler head = new HeadHandler(); PaymentHandler current = head; for (HandlerRule rule : rules) { PaymentHandler handler = registry.instantiate(rule.getHandlerId()); // 应用规则特定的配置 handler.configure(rule.getConfiguration()); current = current.setNext(handler); } return head; } private List<PaymentHandler> selectHandlers(PaymentRequest request) { return allHandlers.stream() .filter(h -> h.supports(new PaymentContext(request))) .collect(Collectors.toList()); } } /** * 客户端使用:支付服务 */ @Service public class ChainBasedPaymentService { private final PaymentChainFactory chainFactory; private final PaymentContextFactory contextFactory; private final PaymentResultAssembler resultAssembler; public PaymentResult process(PaymentRequest request) { // 构建上下文 PaymentContext context = contextFactory.create(request); // 获取合适的处理链 PaymentHandler chain = chainFactory.buildCustomChain(request); // 执行处理链 PaymentContext resultContext = chain.handle(context); // 组装响应 return resultAssembler.assemble(resultContext); } }

四、责任链模式的高级主题

4.1 异步责任链:响应式处理

java
/** * 异步处理者:基于CompletableFuture的非阻塞链 */ public abstract class AsyncPaymentHandler { private AsyncPaymentHandler next; public CompletableFuture<PaymentContext> handle(PaymentContext context) { return doHandle(context) .thenCompose(result -> { if (result.getDecision() == Decision.TERMINATE) { return CompletableFuture.completedFuture(result.getContext()); } if (next != null) { return next.handle(result.getContext()); } return CompletableFuture.completedFuture(result.getContext()); }); } protected abstract CompletableFuture<HandleResult> doHandle(PaymentContext context); } // 使用示例 public CompletableFuture<PaymentResult> processAsync(PaymentRequest request) { PaymentContext context = contextFactory.create(request); AsyncPaymentHandler chain = asyncChainFactory.build(request); return chain.handle(context) .thenApply(resultAssembler::assemble); }

4.2 树形责任链:条件分支

java
/** * 条件分支处理者:根据条件选择不同后继 */ public class ConditionalBranchHandler extends PaymentHandler { private final Map<Predicate<PaymentContext>, PaymentHandler> branches; private PaymentHandler defaultBranch; @Override protected HandleResult doHandle(PaymentContext context) { for (Map.Entry<Predicate<PaymentContext>, PaymentHandler> entry : branches.entrySet()) { if (entry.getKey().test(context)) { return entry.getValue().handle(context).toContinueResult(); } } if (defaultBranch != null) { return defaultBranch.handle(context).toContinueResult(); } return HandleResult.continueWith(context); } }

五、责任链模式与相关模式的辨析

责任链 vs 装饰器:装饰器层层包装,所有对象都处理请求;责任链逐个传递,只有一个对象处理请求。装饰器是"全参与",责任链是"单选中"。

责任链 vs 策略:策略模式选择单一算法,责任链模式多个处理者竞争。策略是"多选一",责任链是"逐个试"。

责任链 vs 命令模式:命令模式封装请求为对象,责任链模式传递请求给处理者。命令关注"请求是什么",责任链关注"谁来处理"。

六、设计陷阱与规避策略

陷阱一:链断裂

未设置后继或后继设置错误导致请求丢失。解决方案:强制链尾处理者返回终止结果,或使用哨兵处理者。

陷阱二:循环链

处理者A的后继是B,B的后继是A。解决方案:链构建时检测环,或使用有向无环图结构。

陷阱三:性能损耗

链过长导致请求传递开销大。解决方案:动态优化链结构,缓存支持判断结果,或扁平化为规则引擎。

七、结语

责任链模式是流程解耦的核心工具,它将请求的处理逻辑分散到独立的处理者中,通过链式结构动态组合。在支付路由、审批流程、异常处理、中间件管道等场景中,责任链模式是不可或缺的架构模式。理解其同步/异步形态、条件分支扩展、动态链编排等高级机制,掌握与规则引擎、响应式编程的融合,警惕链断裂、循环链、性能损耗等工程陷阱,是构建灵活可扩展流程系统的能力核心。责任链模式的精髓在于承认处理逻辑的分散本质,以链为组织形式,在分散与统一之间寻找最优的协作平衡点

返回知识中心