一 引入
在实际开发中的应用 扩展springboot内置异常拦截器–自定义全局异常处理组件 可参考笔者文章
Chain of Responsibility模式名为责任链模式,是一种行为型模型,使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
首先看看什么叫推卸责任,我们去公司申请财务报销,当找到财务时填写报销单后,被告知金额太大只能找财务主管批,于是我们拿着资料去找财务主管,财务主管说金额还是太大只能找老板批。这里相当于将责任传递下去即推卸责任。原因是每个财务能审批的最大金额是不一样的
通过上面的报销例子,我们可以看到自己因为报销找了很多人,这些人相当于一个链条,即第一个不能解决那么找第二个(财务主管),第二个不能解决找第三个(老板)直到找到到底该谁来进行审批即谁来处理。
二 uml 类图
- Handler : 抽象的处理者, 定义了一个处理请求的接口, 同时含义另外Handler
- ConcreteHandlerA , B 是具体的处理者, 处理它自己负责的请求, 可以访问它的后继者(即下一个处理者), 如果可以处理当前请求,则处理,否则就将该请求交个 后继者去处理,从而形成一个职责链
- Request 含义很多属性,表示一个请求
二 代码实现
定义接口及公用抽象
public interface Financial {
/**
* 报账处理
* @param reimbursement
*/
void process(Reimbursement reimbursement);
/**
* 下一个处理节点
* @param financial
* @return
*/
Financial nextFinancial(Financial financial);
}
public abstract class AbstractFinancial implements Financial {
private Financial financial;
@Override
public void process(Reimbursement reimbursement) {
// 通过模板方法定义子类的处理
if (!doProcess(reimbursement)&&this.financial!=null){
// 下节点处理
financial.process(reimbursement);
}
}
@Override
public Financial nextFinancial(Financial financial) {
this.financial=financial;
return financial;
}
abstract Boolean doProcess(Reimbursement reimbursement);
public void outMessage(String name,String reimbursementName){
String format = String.format("%s有权限处理%s的报账", name, reimbursementName);
System.out.println(format);
}
}
定义具体实现
public class Finance extends AbstractFinancial{
@Override
Boolean doProcess(Reimbursement reimbursement) {
if (reimbursement.getAmount()<2000D){
outMessage("财务",reimbursement.getName());
return Boolean.TRUE;
}
return Boolean.FALSE;
}
}
public class Manager extends AbstractFinancial{
@Override
Boolean doProcess(Reimbursement reimbursement) {
if (reimbursement.getAmount()<5000D){
outMessage("财务总监",reimbursement.getName());
return Boolean.TRUE;
}
return Boolean.FALSE;
}
}
public class CFO extends AbstractFinancial{
@Override
Boolean doProcess(Reimbursement reimbursement) {
outMessage("boos",reimbursement.getName());
return Boolean.TRUE;
}
}
提供对外管理器
public class FinancialManger {
public static Financial financial;
static {
Finance finance = new Finance();
Manager manager = new Manager();
CFO cfo = new CFO();
// 设置关系
finance.nextFinancial(manager);
manager.nextFinancial(cfo);
financial=finance;
}
}
三 客户端调用
public class Client {
public static void main(String[] args) {
Reimbursement reimbursement = new Reimbursement();
reimbursement.setAmount(500D);
reimbursement.setName("test1");
FinancialManger.financial.process(reimbursement);
}
}
四 在源码中的应用
五 总结
-
将请求和处理分开,实现解耦,提高系统的灵活性
-
简化了对象,使对象不需要知道链的结构
-
性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在 Handler 中设置一个最大节点数量,在 setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识地破坏系统性能
-
调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂