责任链模式详解及应用实例
一、责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下一个处理者。
核心思想
- 避免请求发送者与接收者耦合在一起
- 让多个对象都有机会处理请求
- 将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止
二、模式结构
主要角色
-
Handler(抽象处理者)
- 定义一个处理请求的接口
- 通常包含一个指向下一个处理者的引用
-
ConcreteHandler(具体处理者)
- 实现抽象处理者的处理方法
- 判断能否处理本次请求,如果可以则处理,否则将请求转发给下一个处理者
-
Client(客户端)
- 创建处理链,并向链头的具体处理者对象提交请求
UML类图
[Client] --> [Handler]
[Handler] <|-- [ConcreteHandler1]
[Handler] <|-- [ConcreteHandler2]
[Handler] o--> [Handler]
三、代码实现示例
Java实现
// 抽象处理者
abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRequest(Request request);
}
// 具体处理者A
class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getType().equals("TypeA")) {
System.out.println("ConcreteHandlerA处理了请求:" + request.getContent());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 具体处理者B
class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getType().equals("TypeB")) {
System.out.println("ConcreteHandlerB处理了请求:" + request.getContent());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 请求类
class Request {
private String type;
private String content;
public Request(String type, String content) {
this.type = type;
this.content = content;
}
// getter方法...
}
// 客户端
public class Client {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
// 构建责任链
handlerA.setNextHandler(handlerB);
// 创建请求
Request request1 = new Request("TypeA", "请求A");
Request request2 = new Request("TypeB", "请求B");
Request request3 = new Request("TypeC", "请求C");
// 处理请求
handlerA.handleRequest(request1);
handlerA.handleRequest(request2);
handlerA.handleRequest(request3);
}
}
四、应用场景
典型应用场景
- 多级请求处理:如审批流程、异常处理等
- 动态指定处理对象:需要在不明确指定接收者的情况下,向多个对象中的一个提交请求
- 可插拔的处理机制:需要动态地组合处理流程
实际应用案例
- Java Servlet中的Filter机制
- Spring Security的认证流程
- 企业审批系统(请假、报销等)
- 日志系统的多级别处理
- 游戏中的事件处理系统
五、责任链模式在审批系统中的应用实例
需求描述
设计一个请假审批系统,规则如下:
- 请假1天以内,组长审批
- 请假1-3天,部门经理审批
- 请假3-7天,总监审批
- 请假7天以上,CEO审批
实现代码
// 请假请求类
class LeaveRequest {
private String name; // 请假人
private int days; // 请假天数
private String reason; // 请假原因
public LeaveRequest(String name, int days, String reason) {
this.name = name;
this.days = days;
this.reason = reason;
}
// getter方法...
}
// 抽象审批者
abstract class Approver {
protected Approver nextApprover;
protected String name;
public Approver(String name) {
this.name = name;
}
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
public abstract void processRequest(LeaveRequest request);
}
// 组长审批
class GroupLeader extends Approver {
public GroupLeader(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 1) {
System.out.printf("组长%s审批了%s的请假申请,天数:%d,原因:%s%n",
name, request.getName(), request.getDays(), request.getReason());
} else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// 部门经理审批
class DepartmentManager extends Approver {
public DepartmentManager(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() > 1 && request.getDays() <= 3) {
System.out.printf("部门经理%s审批了%s的请假申请,天数:%d,原因:%s%n",
name, request.getName(), request.getDays(), request.getReason());
} else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// 总监审批
class Director extends Approver {
public Director(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() > 3 && request.getDays() <= 7) {
System.out.printf("总监%s审批了%s的请假申请,天数:%d,原因:%s%n",
name, request.getName(), request.getDays(), request.getReason());
} else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// CEO审批
class CEO extends Approver {
public CEO(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() > 7) {
System.out.printf("CEO%s审批了%s的请假申请,天数:%d,原因:%s%n",
name, request.getName(), request.getDays(), request.getReason());
} else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// 客户端
public class LeaveSystem {
public static void main(String[] args) {
// 创建审批人
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);
// 创建请假请求
LeaveRequest request1 = new LeaveRequest("张三", 1, "生病");
LeaveRequest request2 = new LeaveRequest("李四", 3, "结婚");
LeaveRequest request3 = new LeaveRequest("王五", 5, "旅游");
LeaveRequest request4 = new LeaveRequest("赵六", 10, "探亲");
// 提交审批
groupLeader.processRequest(request1);
groupLeader.processRequest(request2);
groupLeader.processRequest(request3);
groupLeader.processRequest(request4);
}
}
六、责任链模式的优缺点
优点
- 降低耦合度:请求发送者无需知道哪个对象会处理其请求
- 增强灵活性:可以动态地添加或修改处理链
- 明确责任:每个处理者只需处理自己该处理的部分,不该处理的传递给下一个对象
- 可扩展性强:新增具体处理者无需修改原有代码,符合开闭原则
缺点
- 请求可能未被处理:请求可能到达链的末端仍得不到处理
- 性能问题:请求可能需要在链上传递较长时间才能被处理
- 调试困难:请求的传递是隐式的,调试时可能不太直观
七、模式扩展与变体
-
纯与不纯的责任链模式
- 纯责任链模式:要么处理请求,要么传递给下一个处理者,不能既处理又传递
- 不纯责任链模式:允许处理者既处理请求又传递给下一个处理者
-
功能链:将责任链模式与功能链结合,每个处理者完成请求的一部分处理
-
模式:类似责任链,但处理者可以拦截请求并决定是否继续传递
八、与其他模式的关系
- 与命令模式:责任链模式可以配合命令模式使用,将请求封装为命令对象
- 与组合模式:责任链模式常与组合模式结合使用,处理组合结构中的组件
- 与装饰器模式:两者都基于递归组合,但目的不同。装饰器模式是添加功能,责任链模式是处理请求
责任链模式是一种非常实用的设计模式,特别适合处理具有多级处理逻辑的场景。通过合理使用责任链模式,可以使代码更加灵活、可扩展,并降低系统的耦合度。