文章目录
- 1、责任链模式
- 2、案例:批假
- 3、在源码中的实际应用
1、责任链模式
一个请求可以有多个对象处理,但这些对象能处理的权限不同。比如公司请假,部门负责人、副经理、经理都能批,但他们能批的最大天数不一样。每次让员工直接找自己请假天数对应领导,很麻烦。员工要记录所有信息不说,任何一个领导权限变更,员工记录的信息都要跟着变。因此,考虑如下改进:
三个请求处理者(领导)连成一条线,现在张三来请假,只需找其部分负责人即可,部门负责人看张三请假的天数,自己能批准就批准,不能批准就找他自己的上级(副总经理),以此类推。
责任链模式,即:为了避免请求发送者和多个请求处理者耦合在一起,让所有请求处理者通过下一对象的引用连成一条链。请求过来,沿着这条链走,直到有对象处理它。
结构角色:
- 抽象处理者:接口或抽象类,包含抽象处理方法 + 一个后继连接
- 具体处理者:实现上面的抽象处理方法,判断能否处理本次请求,能则处理,不能则将请求转给后继者
- 客户类:创建处理链,向链头的具体处理者提交请求,但不用关系请求的传递过程
2、案例:批假
需求:请假流程控制,一天以下只需小组长同意,1到3天需要部门经理同意,3到7天需要总经理同意。很明显,请求有多个处理者,且处理的范围和权限不同 ⇒ 责任链
先定义请假条这个业务类:
//请假条
@Getter
public class LeaveRequest {
private String name;//姓名
private int num;//请假天数
private String content;//请假内容
public LeaveRequest(String name, int num, String content) { //有参构造完成初始化
this.name = name;
this.num = num;
this.content = content;
}
}
定义抽象处理者类,除了业务属性外,里面有一个后继者属性。注意两个方法:
- 抽象方法:给各个处理请求的类去继承实现
- 一个后继连接方法:final修饰,定好处理逻辑
//处理者抽象类
public abstract class Handler {
//常量
protected final static int NUM_ONE = 1;
protected final static int NUM_THREE = 3;
protected final static int NUM_SEVEN = 7;
//该领导处理的请假天数区间
private int numStart;
private int numEnd;
//领导上面还有领导(后继者)
private Handler nextHandler;
//设置请假天数范围
public Handler(int numStart, int numEnd) {
this.numStart = numStart;
this.numEnd = numEnd;
}
//设置上级领导
public void setNextHandler(Handler nextHandler){
this.nextHandler = nextHandler;
}
!!!抽象方法
//各级领导处理请假条方法
protected abstract void handleLeave(LeaveRequest leave);
!!!final方法
//提交请假条(final的,子类不能重写)
public final void submit(LeaveRequest leave){
//如果请假天数达到该领导者的处理要求
if(leave.getNum() >= this.numStart){
this.handleLeave(leave);
//如果还有上级 并且请假天数超过了当前领导的处理范围
if(null != this.nextHandler && leave.getNum() > numEnd){
this.nextHandler.submit(leave);//继续提交!!!
} else {
System.out.println("流程结束");
}
}
}
}
定义具体的处理者,继承抽象处理:小组长
//小组长
public class GroupLeader extends Handler {
public GroupLeader() {
//小组长处理0-1天的请假
super(0, Handler.NUM_ONE);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("小组长审批:同意。");
}
}
具体处理者:部门经理
//部门经理
public class Manager extends Handler {
public Manager() {
//部门经理处理1-3天的请假
super(Handler.NUM_ONE, Handler.NUM_THREE);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("部门经理审批:同意。");
}
}
具体处理者:总经理
//总经理
public class GeneralManager extends Handler {
public GeneralManager() {
//部门经理处理3-7天的请假
super(Handler.NUM_THREE, Handler.NUM_SEVEN);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("总经理审批:同意。");
}
}
测试,这里创建各级领导对象,并set他们的NextHandler属性,建立起责任链。如果实战中上级领导人都是固定的,则可以移到领导实现类中去Set。
//测试类
public class Client {
public static void main(String[] args) {
//请假条来一张
LeaveRequest leave = new LeaveRequest("小明",1,"身体不适");
//各位领导
GroupLeader groupLeader = new GroupLeader();
Manager manager = new Manager();
GeneralManager generalManager = new GeneralManager();
//建立责任链
groupLeader.setNextHandler(manager);//小组长的领导是部门经理
manager.setNextHandler(generalManager);//部门经理的领导是总经理
//之所以在这里设置上级领导,是因为可以根据实际需求来更改设置,如果实战中上级领导人都是固定的,则可以移到领导实现类中。
//提交申请(找责任链的链头处理者)
groupLeader.submit(leave);
}
}
运行:
如此实现,扩展性强很强:如果以后要加个总监审批,那就再定义个具体处理者类,set进责任链即可。也可动态删除某个处理者。
3、在源码中的实际应用
模拟示意责任链模式在JavaWeb源码中的应用。先写接口模拟web请求对象Request和web响应对象Response:
public interface Request{
}
public interface Response{
}
模拟web过滤器Filter:
public interface Filter {
public void doFilter(Request req,Response res,FilterChain c);
}
两个具体的过滤器:
public class FirstFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
System.out.println("过滤器1 前置处理");
// 先执行所有request再倒序执行所有response
chain.doFilter(request, response);
System.out.println("过滤器1 后置处理");
}
}
public class SecondFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
System.out.println("过滤器2 前置处理");
// 先执行所有request再倒序执行所有response
chain.doFilter(request, response);
System.out.println("过滤器2 后置处理");
}
}
过滤器链类FilterChain:
public class FilterChain {
private List<Filter> filters = new ArrayList<Filter>();
private int index = 0;
// 链式调用
public FilterChain addFilter(Filter filter) {
this.filters.add(filter);
return this;
}
public void doFilter(Request request, Response response) {
if (index == filters.size()) {
return;
}
Filter filter = filters.get(index);
index++;
//调用过滤器链里每个子过滤器重写的doFilter方法
filter.doFilter(request, response, this);
}
}
测试类:
public class Client {
public static void main(String[] args) {
Request req = null; //占位
Response res = null ;
//过滤器链
FilterChain filterChain = new FilterChain();
//添加过滤器
filterChain.addFilter(new FirstFilter()).addFilter(new SecondFilter());
filterChain.doFilter(req,res);
}
}