1.概述

(1)在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。

(2)责任链模式:又名职责链模式,它将请求的发送者和接收者解耦,并将处理请求的对象组织成一个链条,每个对象都有机会处理请求,如果无法处理,则将请求传递给链条中的下一个对象,直到请求得到处理为止

2.结构

职责链模式主要包含以下角色:

  • 抽象处理者 (Abstract Handler) 角色:定义了处理请求的接口,通常包含一个指向下一个处理者的引用,用于将请求传递给下一个处理者。
  • 具体处理者 (Concrete Handler) 角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 客户类 (Client) 角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

3.案例实现

现需要开发一个请假流程控制系统。请假一天以下的假只需要小组长同意即可;请假 1 天到 3 天的假还需要部门经理同意;请求3天到7天还需要总经理同意才行。
在这里插入图片描述
具体实现代码如下:

3.1.具体请求

LeaveRequest.java

//请假条类
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;
    }
    
    public String getName() {
        return name;
    }
    
    public int getNum() {
        return num;
    }
    
    public String getContent() {
        return content;
    }
}

3.2.抽象处理者

Handler

//抽象处理者
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) {
        this.numStart = numStart;
    }
    
    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);
    
    //提交请假条
    public final void submit(LeaveRequest leave){
        if (this.nextHandler != null && leave.getNum() > this.numEnd) {
            //提交给上级领导进行审批
            this.nextHandler.submit(leave);
        } else {
            //该领导进行审批
            this.handleLeave(leave);
            System.out.println("请假流程结束!");
        }
    }
}

3.3.具体处理者

GroupLeader.java

//小组长类
public class GroupLeader extends Handler{
    public GroupLeader() {
        super(0, Handler.NUM_ONE);
    }
    
    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("小组长审批: 同意");
    }
}

Manager.java

//小组长类
public class Manager extends Handler{
    public Manager() {
        super(Handler.NUM_ONE,Handler.NUM_THREE);
    }
    
    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("部门经理审批: 同意");
    }
}

GeneralManager.java

//小组长类
public class GeneralManager extends Handler{
    public GeneralManager() {
        super(Handler.NUM_THREE, Handler.NUM_SEVEN);
    }
    
    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("总经理审批: 同意");
    }
}

3.4.测试

Client.java

public class Client {
    public static void main(String[] args) {
        //创建一个请假条对象
        LeaveRequest leave = new LeaveRequest("小明", 2, "身体不适");
        
        //创建各级领导对象
        GroupLeader groupLeader = new GroupLeader();
        Manager manager = new Manager();
        GeneralManager generalManager = new GeneralManager();
    
        //设置处理者链
        groupLeader.setNextHandler(manager);
        manager.setNextHandler(generalManager);
    	
        //小明提交请假申请
        groupLeader.submit(leave);
    }
}

4.优缺点以及应用场景

(1)优点

  • 解耦发送者和接收者:责任链模式将发送者和接收者解耦,发送者无需知道具体的接收者是谁,只需将请求发送给链条的起始处理者即可。这样可以简化系统的设计,降低组件之间的耦合度。
  • 动态的处理链:责任链模式允许在运行时动态地组织处理链条,可以灵活地添加、删除或重新排序处理者。这样可以根据实际需求来配置处理流程,提高代码的灵活性。
  • 增强可扩展性:由于责任链模式将请求的处理逻辑分散在多个处理者中,因此可以方便地增加新的处理者来扩展系统的功能。
  • 简化对象之间的交互:责任链模式使得请求的发送者无需知道请求将如何被处理以及具体的处理者是谁,可以直接发送请求给链条的起始处理者。这样简化了对象之间的交互,使得系统更加简洁易懂。

(2)缺点

  • 请求处理不一定被保证:链条中的每个处理者都有机会处理请求,但无法保证请求一定会被处理,可能会出现漏处理的情况。如果没有正确设置处理者链条,可能导致请求无法得到处理。
  • 可能引起性能问题:由于请求在责任链中传递直到被处理,如果处理者链太长或者处理过程复杂,可能会导致性能下降。每个处理者都需要遍历整个链条来判断是否需要处理请求,这可能会影响系统的性能。
  • 可能导致系统难以调试:责任链模式中的请求在多个处理者之间传递,处理逻辑分散在多个处理者中,这可能会使得系统的调试变得困难。当出现问题时,可能需要逐个追踪处理者链,确定问题出现的具体位置。

(3)应用场景

  • 请求处理流程:责任链模式常被用于处理请求的场景,例如审批流程、订单处理流程、请求派发等。每个处理者可以负责处理请求的一部分,并将请求传递给下一个处理者,直到请求得到处理为止。
  • 日志记录:责任链模式可以用于实现日志记录器的链式调用,每个日志记录器负责处理特定级别的日志,然后将日志传递给下一个记录器。这样可以灵活地配置日志级别和目标,例如将日志同时输出到控制台和文件中。
  • 异常处理:责任链模式可以用于处理异常的场景,每个处理者可以负责处理一种特定类型的异常,并将异常传递给下一个处理者,直到异常得到处理或被捕获为止。
  • 消息传递系统:责任链模式可以用于实现消息传递系统,每个处理者负责处理特定类型的消息,并将消息传递给下一个处理者,以实现消息的顺序处理和传递。
  • 链式操作:责任链模式可以用于链式操作的设计,例如函数式编程中的方法链调用,每个处理者可以负责在链式操作中执行特定的操作,并将操作传递给下一个处理者,实现连续的操作流程。

5.源码解析——FilterChain

在 Java Web 应用开发中,FilterChain 是职责链(过滤器)模式的典型应用,以下是 Filter 的模拟实现分析:

(1)模拟web请求Request以及web响应Response

public interface Request{ 
}

public interface Response{ 
}

(2)模拟web过滤器Filter

public interface Filter { 
	public void doFilter(Request req,Response res,FilterChain c); 
}

(3)模拟实现具体过滤器

public class FirstFilter implements Filter {
    public void doFilter(Request req, Response res, FilterChain chain) {
        System.out.println("过滤器1 前置处理");

        // 先执行所有request再倒序执行所有response
        chain.doFilter(req, res);

        System.out.println("过滤器1 后置处理");
    }
}

public class SecondFilter implements Filter {
    public void doFilter(Request req, Response res, FilterChain chain) {
        System.out.println("过滤器2 前置处理");

        // 先执行所有request再倒序执行所有response
        chain.doFilter(req, res);

        System.out.println("过滤器2 后置处理");
    }
}

(4)模拟实现过滤器链 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++;
        filter.doFilter(request, response, this);
    }
}

(5)测试类

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

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

更多推荐