责任链模式
将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象。
场景
打牌时,轮流出牌;接力赛跑;大学中,奖学金审批;公司中,公文审批。
常见的公司内的请假审批流程:如果请假天数小于3天,主任审批;如果请假天数大于等于3天,小于10天,经理审批;如果大于等于10天,小于30天,总经理审批;如果大于等于30天,则自动拒绝。
责任链模式demo
实现这样一个审批,SCM(Supply Chain Management 供应链管理)系统中,采购审批子系统的设计:
采购金额小于5万,主任审批;
采购金额大于等于5万,小于20万,经理审批;
采购金额大于等于20万,总经理审批。
新建PurchaseRequest类封装采购申请的基本信息(申请人姓名,申请金额,用途);新建一个抽象类Leader,然后主任类Director,经理类Manager,总经理类GeneralManager,代码如下所示。
public class PurchaseRequest {
//申请人姓名
private String empName;
//申请金额
private BigDecimal amount;
//申请原因(用途)
private String reason;
public PurchaseRequest(String empName, BigDecimal amount, String reason) {
this.empName = empName;
this.amount = amount;
this.reason = reason;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}
public abstract class Leader {
protected String name;
//责任链上的后继对象
protected Leader nextLeader;
public Leader(String name) {
this.name = name;
}
//设定责任链上的后继对象
public void setNextLeader(Leader nextLeader) {
this.nextLeader = nextLeader;
}
//处理请求的核心的业务方法
public abstract void handleRequest(PurchaseRequest request);
}
public class Director extends Leader{
public Director(String name) {
super(name);
}
@Override
public void handleRequest(PurchaseRequest request) {
if (request.getAmount().compareTo(new BigDecimal(50000)) == -1){
System.out.println("员工:" + request.getEmpName() +
"申请,采购金额" + request.getAmount() +
",原因(用途):" + request.getReason());
System.out.println("主任:" + this.name + ",审批通过!");
} else {
if (nextLeader != null){
this.nextLeader.handleRequest(request);
}
}
}
}
public class Manager extends Leader{
public Manager(String name) {
super(name);
}
@Override
public void handleRequest(PurchaseRequest request) {
if (request.getAmount().compareTo(new BigDecimal(50000)) > -1 &&
request.getAmount().compareTo(new BigDecimal(200000)) == -1){
System.out.println("员工:" + request.getEmpName() +
"申请,采购金额" + request.getAmount() +
",原因(用途):" + request.getReason());
System.out.println("经理:" + this.name + ",审批通过!");
} else {
if (nextLeader != null){
this.nextLeader.handleRequest(request);
}
}
}
}
public class GeneralManager extends Leader{
public GeneralManager(String name) {
super(name);
}
@Override
public void handleRequest(PurchaseRequest request) {
if (request.getAmount().compareTo(new BigDecimal(200000)) < 1){
System.out.println("员工:" + request.getEmpName() +
"申请,采购金额" + request.getAmount() +
",原因(用途):" + request.getReason());
System.out.println("总经理:" + this.name + ",审批通过!");
} else {
System.out.println("采购金额太大,请分批申请!");
}
}
}
public class Client {
public static void main(String[] args) {
Leader a = new Director("张主任");
Leader b = new Manager("李经理");
Leader c = new GeneralManager("赵总");
//组织责任链对象的关系
a.setNextLeader(b);
b.setNextLeader(c);
//开始采购金额审批
PurchaseRequest request = new PurchaseRequest("小明", new BigDecimal(6000),"采购年会礼品!");
a.handleRequest(request);
}
}
当申请金额为6000时,结果如图所示:
如果将金额修改为15万,则运行结果为:
如果公司设置了一个副总经理的职位,然后修改审批流程为:
采购金额小于5万,主任审批;
采购金额大于等于5万,小于10万,经理审批;
采购金额大于等于10万,小于20万,副总经理审批;
采购金额大于等于20万,总经理审批。
只需要新增一个副总经理的类,然后将经理类Manager的审批金额上限修改为10万:
public class ViceGeneralManager extends Leader{
public ViceGeneralManager(String name) {
super(name);
}
@Override
public void handleRequest(PurchaseRequest request) {
if (request.getAmount().compareTo(new BigDecimal(100000)) > -1 &&
request.getAmount().compareTo(new BigDecimal(200000)) == -1){
System.out.println("员工:" + request.getEmpName() +
"申请,采购金额" + request.getAmount() +
",原因(用途):" + request.getReason());
System.out.println("副总经理:" + this.name + ",审批通过!");
} else {
if (nextLeader != null){
this.nextLeader.handleRequest(request);
}
}
}
}
public class Client {
public static void main(String[] args) {
Leader a = new Director("张主任");
Leader b = new Manager("李经理");
Leader c = new ViceGeneralManager("孙副总");
Leader d = new GeneralManager("赵总");
//组织责任链对象的关系
a.setNextLeader(b);
b.setNextLeader(c);
c.setNextLeader(d);
//开始采购金额审批
PurchaseRequest request = new PurchaseRequest("小明", new BigDecimal(150000),"采购年会礼品!");
a.handleRequest(request);
}
}
则运行结果为:
可以看到,当申请金额为15万时,原来由经理审批,现在由副总经理审批,符合需求。
由于责任链的创建完全在客户端,因此新增新的具体处理类对原有类库没有任何影响,只需要添加新类,然后在客户端调用时添加即可。符合开闭原则。
类图
idea自动生成的类图如下所示:
非链表方式实现责任链
以上为链表方式定义职责链的demo。还可以用非链表方式实现职责链。
通过集合、数组生成责任链模式更加实用。实际上,很多项目中,每个具体的handler并不是由开发团队定义的,而是项目上线后由外部单位追加的,所以使用链表方式定义COR链就很困难。
开发中常见的场景
Java中,异常机制就是一种责任链模式。一个try可以对应多个catch,当第一个catch不匹配类型,则自动跳到第二个catch。
Javascript语言中,事件的冒泡和捕获机制。Java语言中,事件的处理采用观察者模式。
Servlet开发中,过滤器的链式处理。
Struts2中,拦截器的调用也是典型的责任链模式。
以上为责任链模式的学习笔记,此文章为尚学堂视频的学习笔记+自己总结。