目录
什么是责任链模式
责任链模式的实现
责任链模式角色
责任链模式类图
责任链模式举例
责任链模式代码实现
责任链模式的特点
优点
缺点
使用场景
注意事项
实际应用
什么是责任链模式
责任链模式(Chain of Responsibility Pattern)又叫职责链模式,是一种行为型设计模式,它通过建立一个对象链来依次处理请求,将请求的发送者和接收者解耦,并允许多个对象都有机会处理请求。其目的是为了解决请求端与实现端的解耦。其实现过程类似递归调用。责任链模式的核心是定义责任链节点的接口以及节点之间的关系,它允许动态的增加和修改责任链中的节点。
责任链模式的实现
责任链模式角色
抽象处理者(Handler):定义了处理请求的接口,并维护一个指向下一处理者的引用。通常包含一个处理方法 handleRequest()。
具体处理者(ConcreteHandler):实现了抽象处理者接口,对请求进行具体处理,如果自身无法处理,则将请求转发给下一处理者。
责任链模式类图
责任链模式举例
以公司采购审批为例,不同金额的采购需要不同人员的审批,比如20000以下需要项目经理审批,20000-50000需要部门经理审批,50000以上需要总经理审批。此时我们把审批流程可以看作一个审批责任链条,进而可以使用责任链模式。
责任链模式代码实现
实体请求类
package com.common.demo.pattern.chain;
import java.math.BigDecimal;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 实体请求类
* @date 2023/07/27 13:35:41
*/
public class PurchaseReq {
/**
* 请求类型
*/
private int type;
/**
* 金额
*/
private BigDecimal price;
/**
* 用途
*/
private String purpose;
public PurchaseReq(int type, BigDecimal price, String purpose) {
this.type = type;
this.price = price;
this.purpose = purpose;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public String getPurpose() {
return purpose;
}
public void setPurpose(String purpose) {
this.purpose = purpose;
}
@Override
public String toString() {
return "PurchaseReq{" +
"type=" + type +
", price=" + price +
", purpose=" + purpose +
'}';
}
}
抽象处理者角色
package com.common.demo.pattern.chain;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 抽象审批者处理类, 抽象处理者角色
* @date 2023/07/27 13:44:42
*/
public abstract class Approver {
Approver approver;
String name;
public Approver() {
}
public Approver(String name) {
this.name = name;
}
/**
* 下一个处理者
*/
public void setApprover(Approver approver) {
this.approver = approver;
}
/**
* 处理审批请求的方法,得到一个请求,处理是子类实现
*/
public abstract void process(PurchaseReq purchaseReq);
}
具体处理者角色
package com.common.demo.pattern.chain;
import java.math.BigDecimal;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 项目经理 具体审批者
* @date 2023/07/27 13:49:16
*/
public class ProjectManager extends Approver {
public ProjectManager(String name) {
super(name);
}
@Override
public void process(PurchaseReq purchaseReq) {
// 小于 5000 项目经理审批即可
if (purchaseReq.getPrice().compareTo(new BigDecimal(5000)) == -1) {
System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,审批终结!");
} else {
System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,进入下一级审批!");
approver.process(purchaseReq);
}
}
}
package com.common.demo.pattern.chain;
import java.math.BigDecimal;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 部门经理 具体审批者
* @date 2023/07/27 13:49:48
*/
public class DepartmentManager extends Approver{
public DepartmentManager(String name) {
super(name);
}
@Override
public void process(PurchaseReq purchaseReq) {
// 小于 20000 大于 5000, 部门经理审批即可
if(purchaseReq.getPrice().compareTo(new BigDecimal(20000))==-1){
System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,审批终结!");
} else {
System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,进入下一级审批!");
approver.process(purchaseReq);
}
}
}
package com.common.demo.pattern.chain;
import java.math.BigDecimal;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 总经理 具体审批者
* @date 2023/07/27 13:50:45
*/
public class GeneralManager extends Approver {
public GeneralManager(String name) {
super(name);
}
@Override
public void process(PurchaseReq purchaseReq) {
// 大于 20000 ,总经理审批
if (new BigDecimal(20000).compareTo(purchaseReq.getPrice()) == -1) {
System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,审批终结!");
} else {
System.out.println("采购计划:"+purchaseReq.getPurpose()+",被"+this.name+"处理,进入下一级审批!");
approver.process(purchaseReq);
}
}
}
测试类
package com.common.demo.pattern.chain;
import java.math.BigDecimal;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 测试类
* @date 2023/07/27 14:23:01
*/
public class Test {
public static void main(String[] args) {
PurchaseReq purchaseRequest1 = new PurchaseReq(1, new BigDecimal(1000), "购买饮水机");
PurchaseReq purchaseRequest2 = new PurchaseReq(2, new BigDecimal(6000), "购买打印机");
PurchaseReq purchaseRequest3 = new PurchaseReq(2, new BigDecimal(30000), "购买苹果笔记本办公");
ProjectManager projectManager = new ProjectManager("项目经理");
DepartmentManager departmentManager = new DepartmentManager("部门经理");
GeneralManager generalManager = new GeneralManager("总经理");
//设置下一级处理人
projectManager.setApprover(departmentManager);
departmentManager.setApprover(generalManager);
//都从项目经理开始处理
projectManager.process(purchaseRequest1);
projectManager.process(purchaseRequest2);
projectManager.process(purchaseRequest3);
}
}
测试截图
责任链模式的特点
优点
- 降低耦合度:将请求和处理分开,请求的发送者和接收者各个组件间完全解耦。
- 简化了对象:使得对象不需知道链的结构,请求者无需知道接受者,无需知道其如何处理。
- 增强灵活性:通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任对象。
- 新增便捷性:增加新的请求处理类很方便。
缺点
- 因为只关心自己内部实现,不关心链内部结构,开发调试会比较麻烦。不容易确认调用的哪一个实现。
- 增加系统的资源消耗。因为链式调用,可能会进行很多次判断,因为每个实现都会判断是否能够处理该请求,不能处理则调用下一个,增加了系统开销。
- 不能保证请求被消化,因其特殊特性,在处理之前会判断是否能够处理,如果每一个链都不能处理,那么该请求无法被消化。
使用场景
- 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
- 可动态指定一组对象处理请求。
注意事项
- 合理设计责任链的节点:责任链模式的核心是将任务分解为一系列的处理节点,每个节点都有机会处理任务或将其传递给下一个节点。在设计责任链节点时,需要根据实际情况合理地划分节点责任,确保每个节点的功能清晰、独立、可扩展,并且能够按需组合形成不同的责任链。
- 灵活配置责任链:责任链模式支持动态配置责任链,也就是可以在运行时通过添加、移除或修改节点来构建不同的责任链。这种灵活性可以根据实际需求动态调整责任链的结构和顺序,但也需要注意避免责任链过长、过于复杂,以及节点的重叠或缺失等问题。
- 节点的执行顺序:责任链模式中,每个节点都有机会处理任务,但处理的顺序是非常重要的。在设计责任链时,需要仔细考虑节点的执行顺序,确保任务能够按照预期的流程依次经过每个节点,同时避免出现死循环或执行顺序混乱等问题。
- 避免责任链的滥用:责任链模式可以很好地解耦请求发送者和接收者之间的关系,但也容易被滥用。在应用责任链模式时,需要审慎选择,确保责任链模式能够带来真正的价值,而不是增加复杂性或降低代码可维护性。
- 错误处理机制:在责任链模式中,如果没有合适的节点处理任务,任务可能会无法得到处理或处理结果不符合预期。因此,在设计责任链时,需要考虑错误处理机制,例如设置默认处理节点、定义异常处理策略等,以确保任务能够得到妥善处理,并且在发生异常时能够及时进行处理和反馈。
实际应用
- Spring框架中的拦截器:拦截器是Spring框架中的一种常见组件,它可以在请求处理前后进行一些额外的处理,例如身份验证、日志记录、权限控制等。拦截器就是利用了责任链模式来将多个处理对象构成一条拦截器链,然后逐个处理请求。Spring框架提供了很多拦截器,例如HandlerInterceptor、WebRequestInterceptor等。
- Servlet中的过滤器:Servlet中的过滤器也是一种常见的使用责任链模式的场景。过滤器可以在请求处理前后进行一些额外的处理,例如安全认证、数据预处理、异常处理等。
- Java 8中的Lambda表达式:Java 8中的Lambda表达式可以看作是一种函数式接口,它利用责任链模式来组合、封装和传递函数对象。Lambda表达式可以通过链式结构形成一个函数的序列,然后按顺序逐个执行这些函数并返回结果,从而可以在Java中实现函数式编程。
- Netty中的处理器Pipeline:Netty是一种基于事件驱动的网络通信框架,它利用责任链模式和事件监听机制来处理请求。Netty中的处理器Pipeline是一条处理请求的链,该链中的每个处理器都可以对请求进行处理和传递,从而形成一个完整的事件处理流程。
更多消息资讯,请访问昂焱数据(https://www.ayshuju.com)