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);
    }
}

在这里插入图片描述

4、其他实际场景

在这里插入图片描述
以下为订单服务的Demo实现。业务订单类:

import java.math.BigDecimal;

@Data
public class OrderInfo {

    private String productId;
    private String userId;

    private BigDecimal amount;
}

定义抽象处理者,具体的处理过程,由具体处理类实现:

/**
 * 抽象处理者
 */
public abstract class Handler {

    protected Handler handler;

    public void setNext(Handler handler) {
        this.handler = handler;
    }

    /**
     * 处理过程
     * 需要子类进行实现
     */
    public abstract void process(OrderInfo order);
}

针对上面的流程写具体处理类:校验参数 ⇒ 填充订单 ⇒ 算价钱 ⇒ 落库

/**
 * 订单校验
 */
public class OrderValidition extends Handler {

    @Override
    public void process(OrderInfo order) {
        System.out.println("校验订单基本信息");
        //校验
        handler.process(order);
    }

}
/**
 * 补充订单信息
 */
public class OrderFill extends Handler {
    @Override
    public void process(OrderInfo order) {
        System.out.println("补充订单信息");
        handler.process(order);
    }

}
/**
 * 计算金额
 */
public class OrderAmountCalcuate extends Handler {
    @Override
    public void process(OrderInfo order) {
        System.out.println("计算金额-优惠券、VIP、活动打折");
        handler.process(order);
    }

}
/**
 * 订单入库
 */
public class OrderCreate extends Handler {
    @Override
    public void process(OrderInfo order) {
        System.out.println("订单入库");
    }
}

写客户端类,把整个链条建立起来:

public class Application {

    public static void main(String[] args) {
        //检验订单
        Handler orderValidition = new OrderValidition();
        //补充订单信息
        Handler orderFill = new OrderFill();
        //订单算价
        Handler orderAmountCalcuate = new OrderAmountCalcuate();
        //订单落库
        Handler orderCreate = new OrderCreate();

        //设置责任链路
        orderValidition.setNext(orderFill);
        orderFill.setNext(orderAmountCalcuate);
        orderAmountCalcuate.setNext(orderCreate);

        //开始执行
        orderValidition.process(new OrderInfo());
    }


}

效果:

在这里插入图片描述

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐