简介
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
主要有两个核心行为:1.处理请求;2.将请求传递到下一节点
UML图:
应用场景
- Apache Tomcat 对 Encoding 编码的处理,Springboot 中的拦截器和过滤器链
- 存在多个对象可以处理同一个请求,但具体哪个请求进行处理由运行时动态决定
- 日志级别:debugger -> info -> warning -> error
示例
金融行业的一些风控规则,受限于一些政策会经常进行调整,不同的交易金额有不同的风控策略进行处理
- Client:
java
public class Request {
/**
* 金额
*/
private double money;
/**
* 请求类型
*/
private String requestType;
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public String getRequestType() {
return requestType;
}
public void setRequestType(String requestType) {
this.requestType = requestType;
}
}
- Handler:
java
public abstract class RiskManager {
/**
* 防控策略
*/
protected String riskName;
/**
* 上级防控
*/
protected RiskManager superior;
public RiskManager(String riskName) {
this.riskName = riskName;
}
/**
* 处理请求
*
* @param request
*/
public abstract void handleRequest(Request request);
public RiskManager getSuperior() {
return superior;
}
public void setSuperior(RiskManager superior) {
this.superior = superior;
}
}
一级防控:
java
public class FirstRiskManager extends RiskManager {
public FirstRiskManager(String riskName) {
super(riskName);
}
@Override
public void handleRequest(Request request) {
if ("线上".equals(request.getRequestType()) && 2000 > request.getMoney()) {
System.out.println("支付方式:" + request.getRequestType() + ",支付金额:" + request.getMoney() + ",防控策略:" + riskName);
} else {
if (null != superior) {
// 触发其他防控策略
superior.handleRequest(request);
}
}
}
}
二级防控:
java
public class SecondRiskManager extends RiskManager {
public SecondRiskManager(String riskName) {
super(riskName);
}
@Override
public void handleRequest(Request request) {
if ("线上".equals(request.getRequestType()) && 5000 > request.getMoney()) {
System.out.println("支付方式:" + request.getRequestType() + ",支付金额:" + request.getMoney() + ",防控策略:" + riskName);
} else {
System.out.println("支付方式:" + request.getRequestType() + ",支付金额:" + request.getMoney() + ",防控策略:限制交易!");
}
}
}
- 运行
java
public class Main {
public static void main(String[] args) {
FirstRiskManager firstRiskManager = new FirstRiskManager("一级防控,正常交易");
SecondRiskManager secondRiskManager = new SecondRiskManager("二级防控,重点监控");
firstRiskManager.setSuperior(secondRiskManager);
Request request = new Request();
request.setRequestType("线上");
// 一级防控
request.setMoney(1200);
firstRiskManager.handleRequest(request);
// 二级防控
request.setMoney(4000);
firstRiskManager.handleRequest(request);
// 最终防控
request.setMoney(6000);
firstRiskManager.handleRequest(request);
}
}
总结
- 优点
- 客户只需要将请求发送到职责链上即可,无需关心请求的具体细节,降低了耦合度
- 通过改变链内的调动次序,可以动态新增或删除处理类,提高了可维护性
- 可以根据需求新增请求处理类,提高了可扩展性,同时满足开闭原则
- 每个请求处理类只服务于自己的责任范围,满足单一职责原则
- 缺点
- 要把整个流程走完,可能需要很多的职责对象,可能会造成系统性能降低,同时产生大量的细粒度职责对象,并且出现问题不方便调试
- 不能保证请求一定被接收