Hello 大家好,我是阿粉,工作中我们经常会遇到很多需要上级或者上级的上级一层层审批的流程,作为程序员如果要让你实现这个流程,你会采用什么方式呢?
好了思考一分钟结束,很显然大家一致的回答就是责任链模式。那么什么是责任链模式呢?如何使用责任链模式去完成这个流程呢?下面我们来看一下。
需求分析
开发之前的第一步是需求分析,我们这个场景是这样的,阿粉准备跟领导 A 申请一下涨薪,最满意的结果当时是直接跟上级领导 A 申请就直接过了,但是理想很丰满,现实很骨干。领导 A 也只是一个小组长并没有直接涨薪的权利,所以领导也要向他的上级 B 进行申请,而然到这里并没有结束,因为 B 还要跟人资管事的 C 进行申请,人事 C 同事最终还要跟 CEO 进行申请。
想想这个流程有多么的负责,不禁的阿粉就不抱希望了,毕竟阿粉只是一个小开发,想涨个工资怎么这么难,阿粉哭晕在厕所。
在这个场景里面有这个几个需求点,就是每个人都有自己的权限,在自己能力范围之内的事情可以直接审批,但是不在自己能力的范围里面只能向上反馈;申请的内容是加薪,最终 CEO 具有最终决策权。
初始版本
首先我们定义一个工单的 model,具体代码如下
代码语言:javascript复制
package com.test.model.chain;
public class ApplyModel {
//申请人名称
private String applyName;
//工单类型
private String type;
//工单内容
private String content;
//涨薪幅度
private int salary;
//...get set 省略
}
初始版本的申请涨薪代码如下,根据不同的领导和不同的申请类型来进行相应的逻辑处理。
代码语言:javascript复制
package com.test.model.chain;
public class ClientApplyServiceDemo {
public void handlerApply(String leader, ApplyModel applyModel) {
if ("A".equals(leader)) {
if ("涨薪".equals(applyModel.getType()) && applyModel.getSalary() < 100) {
System.out.println("小于 100 的涨薪,A 可以直接处理");
} else {
System.out.println("大于 100 的涨薪,A 不能处理");
}
}
if ("B".equals(leader)) {
if ("涨薪".equals(applyModel.getType()) && applyModel.getSalary() < 300) {
System.out.println("小于 300 的涨薪,B 可以直接处理");
} else {
System.out.println("大于 300 的涨薪,B 不能处理");
}
}
if ("C".equals(leader)) {
if ("涨薪".equals(applyModel.getType()) && applyModel.getSalary() < 500) {
System.out.println("小于 500 的涨薪,C 可以直接处理");
} else {
System.out.println("大于 500 的涨薪,C 不能处理");
}
}
if ("CEO".equals(leader)) {
if ("涨薪".equals(applyModel.getType()) && applyModel.getSalary() < 800) {
System.out.println("小于 800 的涨薪,CEO 可以直接处理");
} else {
System.out.println("大于 800 的涨薪,CEO 不能处理,下次吧,别做梦了");
}
}
}
}
上面的代码请勿服用,否则被开除阿粉不背锅。
很显然上面的代码用一个字来形容,那就是烂!两个字就是真烂!!实际工作中要是写出这样的代码,那么恭喜你,你已经走在被炒鱿鱼的路上了。
那么我们如何通过责任链的设计模式让整个代码优雅起来呢?
什么是责任链模式
使多个对象都有处理请求的机会,从而避免请求的发起者和接收者之间的耦合,将这个对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
重构
思考一样,我们有上下级,而且每个领导都有上级以及自己能处理的能力范围,所以我们可以按照下面的类图进行设计,我们可以将申请工单的请求按照职级向上传递,当自己处理不了的时候就反馈给上级,上级完成不了的时候就会传递给他的上级,直到某个级别能处理为止。
首先我们设计一个抽象类 Leader,代码如下
代码语言:javascript复制
package com.test.model.chain.leader;
import com.test.model.chain.ApplyModel;
public abstract class Leader {
protected Leader leader;
public void setLeader(Leader leader) {
this.leader = leader;
}
public abstract void handlerApply(ApplyModel applyModel);
}
下面是具体四个子类,具体的代码如下
代码语言:javascript复制
package com.test.model.chain.leader.impl;
import com.test.model.chain.ApplyModel;
import com.test.model.chain.leader.Leader;
public class ALeader extends Leader {
protected Leader leader;
@Override
public void setLeader(Leader leader) {
this.leader = leader;
}
@Override
public void handlerApply(ApplyModel applyModel) {
if (applyModel.getSalary() < 100) {
System.out.println("申请金额为" applyModel.getSalary() "小于 100,A 可以处理");
} else {
leader.handlerApply(applyModel);
}
}
}
package com.test.model.chain.leader.impl;
import com.test.model.chain.ApplyModel;
import com.test.model.chain.leader.Leader;
public class BLeader extends Leader {
protected Leader leader;
@Override
public void setLeader(Leader leader) {
this.leader = leader;
}
@Override
public void handlerApply(ApplyModel applyModel) {
if (applyModel.getSalary() < 300) {
System.out.println("申请金额为" applyModel.getSalary() "小于 300,B 可以处理");
} else {
leader.handlerApply(applyModel);
}
}
}
package com.test.model.chain.leader.impl;
import com.test.model.chain.ApplyModel;
import com.test.model.chain.leader.Leader;
public class CLeader extends Leader {
protected Leader leader;
@Override
public void setLeader(Leader leader) {
this.leader = leader;
}
@Override
public void handlerApply(ApplyModel applyModel) {
if (applyModel.getSalary() < 500) {
System.out.println("申请金额为" applyModel.getSalary() "小于 500,C 可以处理");
} else {
leader.handlerApply(applyModel);
}
}
}
package test.model.chain.leader.impl;
import test.model.chain.ApplyModel;
import com.test.model.chain.leader.Leader;
public class CEOLeader extends Leader {
protected Leader leader;
@Override
public void setLeader(Leader leader) {
this.leader = leader;
}
@Override
public void handlerApply(ApplyModel applyModel) {
if (applyModel.getSalary() < 1000) {
System.out.println("申请金额为" applyModel.getSalary() "小于 1000,CEO 同意了");
} else {
System.out.println("想涨薪" applyModel.getSalary() "这么多,下次吧");
}
}
}
抽象类中有一个属性,一个构造方法和一个抽象方法;相应的子类分别实现了各自的抽象方法,用来处理各自的能力范围之内的事情。每个实现类根据自身的能力觉得如果处理相应的申请条件,这样的结构可以更加可读,并且每个人的处理能力互不影响,如果谁的能力有变化只要修改自己的那一部分就可以了。接下来我们看下客户端是如果调用的。
代码语言:javascript复制
package com.test.model.chain;
import com.test.model.chain.leader.Leader;
import com.test.model.chain.leader.impl.ALeader;
import com.test.model.chain.leader.impl.BLeader;
import com.test.model.chain.leader.impl.CEOLeader;
import com.test.model.chain.leader.impl.CLeader;
public class ClientApplyService {
public static void main(String[] args) {
ApplyModel applyModel = new ApplyModel();
applyModel.setApplyName("阿粉");
applyModel.setContent("申请涨薪");
applyModel.setSalary(50);
Leader aLeader = new ALeader();
Leader bLeader = new BLeader();
Leader cLeader = new CLeader();
Leader ceoLeader = new CEOLeader();
aLeader.setLeader(bLeader);
bLeader.setLeader(cLeader);
cLeader.setLeader(ceoLeader);
aLeader.handlerApply(applyModel);
}
}
我们分别修改涨薪的幅度数值,看下执行的结果。
申请 50 涨幅的运行结果如下(忽略具体的数值,相信我如果涨工资只涨 50 ,那简直就是侮辱,这种公司还是尽早躲开吧)。
将涨薪幅度调整为 150,运行结果如下。
将涨幅调整为 550,运行结果如下:
将涨幅调整为 1550,运行结果如下:
经过我们的重构,整个代码结构已经非常的清晰了,现在的代码已经比初始版本优雅很多了,使用责任链的好处就是将请求一层层的处理,直到有能处理的对象为止,可以避免耦合。