责任链设计模式是一种行为模式,它允许您沿着处理程序链传递请求,允许每个处理程序决定是处理请求还是将其传递给链中的下一个处理程序。
它在以下情况下特别有用:
请求必须由许多可能的处理程序之一处理,并且您不希望发送方与任何特定处理程序紧密耦合。
你希望将请求逻辑与处理它的代码分离。
您希望灵活地添加、删除或重新排序处理程序,而无需更改客户端代码。
在处理条件请求处理时,开发人员通常求助于长链 的 or 语句来确定应如何处理请求。例如,日志记录系统可能会根据配置写入控制台、文件或远程服务器,或者 HTTP 请求可能需要经历验证、身份验证和速率限制步骤。if-elseswitch
但随着条件数量的增加,这种方法变得难以扩展,违反了开放/关闭原则,并将您的逻辑变成了一个紧密耦合的、脆弱的单体。
责任链模式通过将各个处理步骤转换为独立的类来解决这个问题,每个类负责一个特定的关注点。这些处理程序链接在一起形成一个链,请求流经链,直到被处理(或删除)。
让我们通过一个真实世界的示例,看看如何应用责任链模式来构建一个干净、模块化且可扩展的请求处理管道。
问题:处理具有多个处理步骤的 HTTP 请求
想象一下,您正在构建一个后端服务器,用于处理 Web 应用程序或 RESTful API 的传入 HTTP 请求。
请求可能如下所示:
public class Request {
public String user;
public String userRole;
public int requestCount;
public String payload;
public Request(String user, String role, int requestCount, String payload) {
this.user = user;
this.userRole = role;
this.requestCount = requestCount;
this.payload = payload;
}
}
每个传入请求在 到达核心业务逻辑之前都必须经过一系列处理步骤。
常见预处理步骤
身份验证 – 用户是否正确进行了身份验证(例如,通过令牌或会话)?
授权 – 是否允许经过身份验证的用户执行此作?
速率限制 – 用户是否超过了允许的请求数?
数据验证 – 请求有效负载是否格式正确且有效?
只有在所有这些检查都通过后,请求才能到达实际的业务逻辑(例如,创建资源、返回数据或更新记录)。
典型的第一次尝试可能如下所示:使用长链 or 方法调用实现单个类中的所有逻辑 。if-else
这是一个简化版本:
public class RequestHandler {
public void handle(Request request) {
if (!authenticate(request)) {
System.out.println("Request Rejected: Authentication failed.");
return;
}
if (!authorize(request)) {
System.out.println("Request Rejected: Authorization failed.");
return;
}
if (!rateLimit(request)) {
System.out.println("Request Rejected: Rate limit exceeded.");
return;
}
if (!validate(request)) {
System.out.println("Request Rejected: Invalid payload.");
return;
}
System.out.println("Request passed all checks. Executing business logic...");
// Proceed to business logic
}
private boolean authenticate(Request req) {
return req.user != null;
}
private boolean authorize(Request req) {
return "ADMIN".equals(req.userRole);
}
private boolean rateLimit(Request req) {
return req.requestCount < 100;
}
private boolean validate(Request req) {
return req.payload != null && !req.payload.isEmpty();
}
}
客户端代码示例
public class App {
public static void main(String[] args) {
// 创建请求对象
Request req = new Request("john_doe", "ADMIN", 42, "{ 'data': 123 }");
// 创建处理器并处理请求
RequestHandler handler = new RequestHandler();
handler.handle(req);
}
}
为什么这种方法会失败
虽然这种方法可能适用于少量检查,但它很快就会出现问题:
- 1. 难以扩展或修改
如果要更改检查顺序或添加新检查顺序(例如,日志记录、指标、缓存),则必须修改现有处理程序 — 违反了开放/关闭原则。 - 2. 关注点分离不当
所有验证和控制逻辑都紧密耦合在单个方法中。这违反了单一责任原则,并使代码更难测试和维护。 - 3. 不可重复使用
您无法在系统的其他部分轻松重复使用单个检查(例如,速率限制或身份验证)。 - 4. 配置不灵活
想要跳过公共 API 的授权?想要在开发模式下将验证设为可选?你将不得不编写更多 条件并使处理程序膨胀。if
我们真正需要什么
我们需要一种方法来:
将每个步骤分解为自己的责任单元
让每个步骤决定是处理、传递还是短路请求
允许添加、删除或重新排序新的处理程序,而无需接触现有代码
保持我们的逻辑干净、可测试和可扩展
这就是责任链模式的用武之地。
责任链模式
责任链模式允许沿着处理程序链传递请求。链中的每个处理程序都可以:
处理请求,或
将其传递给链中的下一个处理程序
这种模式将 请求的发送者与接收者解耦,使您可以灵活地动态组合链、重用逻辑并避免冗长、僵化的条件块。
类图

- 1. 处理程序接口(抽象基类/接口)
声明一个方法,例如 用于处理请求。handle(request)
通过 保存对链中下一个处理程序的引用。setNext(handler)
定义将请求向下传递链的合约。 - 2. ConcreteHandlers(例如, AuthHandlerRateLimitHandler)
实现接口 。Handler
每个处理程序决定它是否会:
处理请求(例如,拒绝、记录、转换),或
将请求传递给链中的下一个处理程序。 - 3. 客户
使用 构建和连接处理程序链。 setNext()
将请求发送到 链中的第一个处理程序。
不知道哪个处理程序最终将处理请求。
实施责任链
让我们使用责任链模式将我们的单体重构 为一个干净的、可扩展的模块化处理程序链。RequestHandler
- 1. 定义通用处理程序接口
每个处理程序都会实现这个接口。每个处理程序都应:
执行其特定检查
决定是停止链还是将请求传递给下一个处理程序
public interface RequestHandler {
void setNext(RequestHandler next);
void handle(Request request);
}
- 2. 创建抽象基本处理程序(可选,但推荐)
为了避免 在每个处理程序中重复和转发逻辑,我们定义了一个具有可重用功能的抽象基类。setNext()
public abstract class BaseHandler implements RequestHandler {
protected RequestHandler next;
@Override
public void setNext(RequestHandler next) {
this.next = next;
}
protected void forward(Request request) {
if (next != null) {
next.handle(request);
}
}
}
现在,每个具体处理程序都可以只专注于其逻辑,并在 需要时委派。forward(request)
- 3. 创建具体处理程序
每个处理程序实现一个责任。他们延长、实施并确定是继续链还是短路链。BaseHandlerhandle(Request)
🔐 身份验证处理程序
public class AuthHandler extends BaseHandler {
@Override
public void handle(Request request) {
if (request.user == null) {
System.out.println("AuthHandler: ❌ User not authenticated.");
return; // Stop the chain
}
System.out.println("AuthHandler: ✅ Authenticated.");
forward(request);
}
}
🔒 授权处理程序
public class AuthorizationHandler extends BaseHandler {
@Override
public void handle(Request request) {
if (!"ADMIN".equals(request.userRole)) {
System.out.println("AuthorizationHandler: ❌ Access denied.");
return;
}
System.out.println("AuthorizationHandler: ✅ Authorized.");
forward(request);
}
}
⏱️ 速率限制处理程序
public class RateLimitHandler extends BaseHandler {
@Override
public void handle(Request request) {
if (request.requestCount >= 100) {
System.out.println("RateLimitHandler: ❌ Rate limit exceeded.");
return;
}
System.out.println("RateLimitHandler: ✅ Within rate limit.");
forward(request);
}
}
📦 数据验证处理程序
public class ValidationHandler extends BaseHandler {
@Override
public void handle(Request request) {
if (request.payload == null || request.payload.trim().isEmpty()) {
System.out.println("ValidationHandler: ❌ Invalid payload.");
return;
}
System.out.println("ValidationHandler: ✅ Payload valid.");
forward(request);
}
}
✅ 最终业务逻辑处理程序
这是链中的最后一个处理程序——它假设请求已通过所有先前的检查。
console.log("Hello, Doocs!");
- 4. 在客户端代码中组装链
现在我们的处理程序是模块化的,我们可以根据要求以任何顺序连接它们。
public class BusinessLogicHandler extends BaseHandler {
@Override
public void handle(Request request) {
System.out.println("BusinessLogicHandler: 🚀 Processing request...");
// Core application logic goes here
}
}
输出
AuthHandler: ✅ Authenticated.
AuthorizationHandler: ✅ Authorized.
RateLimitHandler: ✅ Within rate limit.
ValidationHandler: ✅ Payload valid.
BusinessLogicHandler: 🚀 Processing request...
--- Trying an invalid request ---
AuthHandler: ❌ User not authenticated.
我们取得了什么成就
模块化:每个处理器都是隔离的,易于测试
松散耦合:处理者不需要知道谁是下一个
可扩展性:轻松插入、删除或重新排序处理程序
Clean Client Code:只负责构建链和发送请求
开放/关闭兼容:您可以在不接触现有代码的情况下添加新功能(例如 LoggingHandler)
1667

被折叠的 条评论
为什么被折叠?



