目录
责任链模式定义
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
优点
-
解耦发送者和接收者:责任链模式允许请求的发送者和接收者解耦,发送者无需知道请求是由哪个接收者处理的。
-
灵活性:可以动态地向责任链中添加或删除处理者,以适应不同的需求。
-
可维护性:每个处理者只关注自己的任务,使代码更易于维护和扩展。
缺点
-
请求可能无法得到处理:如果责任链的最后一个处理者没有处理请求的逻辑,请求可能会达到链的末端而无法得到处理。
-
性能问题:链中的多个处理者都需要依次尝试处理请求,可能会影响性能,特别是在链较长且处理时间较长的情况下。
责任链模式结构说明
-
Handler(处理者):定义一个处理请求的接口,通常包含一个处理方法。具体的处理者类实现了这个接口。
-
ConcreteHandler(具体处理者):具体处理者是实际处理请求的对象,它实现了处理请求的方法。如果它可以处理请求,就处理请求;否则,将请求传递给链中的下一个处理者。
-
Client(客户端):创建处理请求的对象链,将请求发送给链的第一个处理者。
工作流程
-
客户端创建一个处理请求的对象链,并将请求发送给链的第一个处理者。
-
每个处理者决定是否能够处理请求。如果可以,处理请求并返回结果;如果不能,将请求传递给链中的下一个处理者。
-
请求按照链的顺序传递,直到有一个处理者处理请求或者请求达到链的末端而无法处理。
代码示例
请求在处理者链中传递的场景,最容易想到的就是审批流程了。这里就用请假场景举例吧。
1.请假类,属性有姓名和天数。
public class LeaveRequest { String name; int day; public String getName() { return name; } public int getDay() { return day; } public LeaveRequest(String name, int day) { this.name = name; this.day = day; } }
2.创建抽象类Handle,包含需要传递的处理者引用。
public abstract class Handle { protected Handle successor = null; public void setSuccessor(Handle successor) { this.successor = successor; } protected abstract boolean handleRequest(LeaveRequest request); public final void handle(LeaveRequest request){ boolean handled = handleRequest(request); if (successor != null && !handled) { successor.handle(request); } } }
3.创建具体处理者ProjectManager、DeptManager和GeneralManager。
public class ProjectManager extends Handle{ @Override protected boolean handleRequest(LeaveRequest request) { boolean handled = false; // 3天以下,项目经理可以批假 if (request.getDay() <= 2) { System.out.println("ProjectMange Approved " + request.getName() + " " + request.getDay() + " Leave..."); handled = true; } return handled; } }
public class DeptManager extends Handle{ @Override protected boolean handleRequest(LeaveRequest request) { // 6天以下,部门经理可以批假 if (request.getDay() <= 5) { System.out.println("DeptManager Approved " + request.getName() + " " + request.getDay() + " Leave..."); return true; } return false; } }
public class GeneralManager extends Handle{ @Override protected boolean handleRequest(LeaveRequest request) { // 15天以下,总经理可以批假 if (request.getDay() <= 14) { System.out.println("GeneralManager Approved " + request.getName() + " " + request.getDay() + " Leave..."); return true; } return false; } }
4.客户端调用
public class HandleClient { public static void main(String[] args) { Handle projectManager = new ProjectManager(); Handle deptManager = new DeptManager(); Handle generalManager = new GeneralManager(); projectManager.setSuccessor(deptManager); deptManager.setSuccessor(generalManager); LeaveRequest leaveRequest = new LeaveRequest("小李", 5); projectManager.handle(leaveRequest); } }
结果:
应用场景
-
当需要多个对象处理请求,但不确定哪个对象会处理请求时,可以使用责任链模式。
-
当需要动态指定处理请求的对象集合,并且可以随时添加或删除处理者时,责任链模式非常有用。
-
当希望将请求的发送者和接收者解耦时,责任链模式可以帮助实现。
本质:
责任链模式的本质是解耦请求发送者和接收者,将多个对象组成一条链,并沿着链传递请求,直到有一个对象处理请求为止。
涉及的设计原则
-
单一职责原则(Single Responsibility Principle):每个具体处理者只负责处理一种类型的请求。
-
开闭原则(Open-Closed Principle):责任链模式支持动态地向链中添加或删除处理者,符合开闭原则。
相关设计模式
-
装饰者模式(Decorator Pattern):责任链模式与装饰者模式有些类似,都可以用于动态地添加功能。装饰者模式注重在对象上添加新的行为,而责任链模式注重在一系列对象上分发和处理请求。
-
命令模式(Command Pattern):责任链模式和命令模式都可以用于解耦请求的发送者和接收者。不同之处在于责任链模式是一种传递请求的模式,而命令模式是一种将请求封装为对象的模式。
开源框架中的应用
在Java中,Servlet容器中的Filter链就是责任链模式的应用。每个Filter可以处理HTTP请求并将请求传递给下一个Filter,最终到达Servlet。 Spring框架中的拦截器(Interceptor)链也是责任链模式的应用,用于处理请求前和请求后的逻辑。