意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
优点:
- 降低耦合度。它将请求的发送者和接收者解耦。
- 简化了对象。使得对象不需要知道链的结构。
- 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
- 增加新的请求处理类很方便。
缺点:
- 不能保证请求一定被接收。
- 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
- 可能不容易观察运行时的特征,有碍于除错。
下面用责任链完成一个案例:OA 系统采购审批
需求:
采购员采购教学器材如果金额 小于等于 5000 ,由教学主任审批如果金额 小于等于 10000 ,由院长审批如果金额 小于等于 30000 ,由副校长审批如果金额 超过 30000 以上,由校长审批
分析:
客户端发送一个采购请求,处理请求的角色一共有四个,如果我们用多重
if
语句进行判断编写代
码,就会出现请求与每个处理请求的方法强耦合性,代码会比较臃肿,不利于扩展和维护,这个时候
我们采用责任链模式进行代码设计:
客户端发送一个请求,由一个抽象的处理请求的类
Handler
来接受这个请求,而具体怎么处理请
求,就由
Handler
的子类来完成处理请求方法的实现,这样,每个子类完成自己的功能,日后维护扩展也方便
类图如下:

新建一个 maven 工程 respchain
在项目下新建一个采购请求类 cn.xs.PurchaseRequest :
public class PurchaseRequest {
/* 请求类型 */
private int type = 0;
/* 请求金额 */
private float price = 0.0f;
/* 请求编号 */
private int id = 0;
/**
* 全参构造
*
* @param type
* @param price
* @param id
*/
public PurchaseRequest(int type, float price, int id) {
this.type = type;
this.price = price;
this.id = id;
}
public int getType() {
return type;
}
public float getPrice() {
return price;
}
public int getId() {
return id;
}
}
新建审批抽象类
cn.xs.Approver
:
public abstract class Approver {
/* 审批人姓名 */
protected String name;
/* 下一个审批人 */
protected Approver approver;
/**
* 创建审批人要指定姓名
*
* @param name
*/
public Approver(String name) {
this.name = name;
}
/**
* 指定下一个审批人
*
* @param approver
*/
public void setApprover(Approver approver) {
this.approver = approver;
}
/**
* 抽象的审批方法
*
* @param purchaseRequest
*/
public abstract void approve(PurchaseRequest purchaseRequest);
}
新建四个子类来继承抽象审批类
教学主任:
cn.xs.DepartmentApprover
,代码如下:
public class DepartmentApprover extends Approver {
/**
* 创建审批人要指定姓名
*
* @param name
*/
public DepartmentApprover(String name) {
super(name);
}
/**
* 教学主任审批逻辑
*
* @param purchaseRequest
*/
public void approve(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() <= 5000) {
System.out.println("请求编号:" + purchaseRequest.getId() + "被" +
this.name + "处理");
} else {
approver.approve(purchaseRequest);
}
}
}
院长:
cn.xs.Dean
,代码如下:
public class Dean extends Approver {
/**
* 创建审批人要指定姓名
*
* @param name
*/
public Dean(String name) {
super(name);
}
/**
* 院长审批逻辑
*
* @param purchaseRequest
*/
public void approve(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() > 5000 && purchaseRequest.getPrice() <=
10000) {
System.out.println("请求编号:" + purchaseRequest.getId() + "被" +
this.name + "处理");
} else {
approver.approve(purchaseRequest);
}
}
}
副校长:
cn.xs.VicePrincipal
,代码如下:
public class VicePrincipal extends Approver {
/**
* 创建审批人要指定姓名
*
* @param name
*/
public VicePrincipal(String name) {
super(name);
}
/**
* 副校长审批逻辑
*
* @param purchaseRequest
*/
public void approve(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() > 10000 && purchaseRequest.getPrice() <=
30000) {
System.out.println("请求编号:" + purchaseRequest.getId() + "被" +
this.name + "处理");
} else {
approver.approve(purchaseRequest);
}
}
}
校长:
cn.xs.Principal
,代码如下:
public class Principal extends Approver {
/**
* 创建审批人要指定姓名
*
* @param name
*/
public Principal(String name) {
super(name);
}
/**
* 校长审批逻辑
*
* @param purchaseRequest
*/
public void approve(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() > 30000) {
System.out.println("请求编号:" + purchaseRequest.getId() + "被" +
this.name + "处理");
} else {
approver.approve(purchaseRequest);
}
}
}
创建一个客户端类
cn.xs.Client
模拟客户端发请求测试:
public class Client {
/**
* 测试方法
*
* @param args
*/
public static void main(String[] args) {
// 创建采购请求
PurchaseRequest purchaseRequest = new PurchaseRequest(1, 3000, 1);
// 创建审批人
Approver departmentApprover = new DepartmentApprover("团主任");
Approver dean = new Dean("方院长");
Approver vicePrincipal = new VicePrincipal("磊副校长");
Approver principal = new Principal("喜校长");
// 设置下一个审批人
departmentApprover.setApprover(dean);
dean.setApprover(vicePrincipal);
vicePrincipal.setApprover(principal);
// 这里要形成一个环链,避免如果 30000 金额以下的请求
// 直接交给校长处理,会出现空指针
// 当然,如果程序规定只能从主任开始处理
// 一层一层最后到校长处理,形成一个单链,这里就不用了设置了
principal.setApprover(departmentApprover);
// 测试:
departmentApprover.approve(purchaseRequest);
}
}
责任链在
SpringMVC
框架中的使用:
说明:
SpringMVC
请求的流程图中,执行了拦截器相关方法
interceptor.preHandler
等等
在处理
SpringMVC
请求时,使用到责任链模式还使用到适配器模式
HandlerExecutionChain
主要负责的是请求拦截器的执行和请求处理,但是他本身不处理请求,只
是将请求分配给链上注册的处理器执行,这是责任链实现方式,减少责任链本身与处理逻辑之间的耦合,规范了处理流程 HandlerExecutionChain 维护了
HandlerInterceptor
的集合,可以向其中注册响应的拦截器
责任链模式的注意事项和细节 :将请求与处理分开,实现解耦,提高系统的灵活性简化了对象,是对象不需要知道链的结构性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在 Handler中设置一个最大节点数量,在 setNext() 方法中判断是否已经超过阈值,超过则不允许该链建立,避免出现超长链无意识的破坏系统性能 调试不方便,采用了类似递归的方式,调试时逻辑可能比较复杂 最佳应用场景:有多个对象可以处理同一请求时,比如:多级请求、请假、加薪等审批流程