设计模式-责任链模式

1、概述

职责链模式(Chain Of Responsibility) 是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

包括以下角色:

处理者 (Handler) 声明了所有具体处理者的通用接口。 该接口通常仅包含单个方法用于请求处理, 但有时其还会包含一个设置链上下个处理者的方法。

基础处理者 (Base Handler) 是一个可选的类, 你可以将所有处理者共用的样本代码放置在其中。通常情况下, 该类中定义了一个保存对于下个处理者引用的成员变量。 客户端可通过将处理者传递给上个处理者的构造函数或设定方法来创建链。 该类还可以实现默认的处理行为: 确定下个处理者存在后再将请求传递给它。

具体处理者 (Concrete Handlers) 包含处理请求的实际代码。 每个处理者接收到请求后, 都必须决定是否进行处理, 以及是否沿着链传递请求。处理者通常是独立且不可变的, 需要通过构造函数一次性地获得所有必要地数据。

客户端 (Client) 可根据程序逻辑一次性或者动态地生成链。 值得注意的是, 请求可发送给链上的任意一个处理者, 而非必须是第一个处理者。

2、优缺点

优点:

解耦发送者和接收者:责任链模式将请求的发送者和接收者解耦,发送者无需知道具体的处理对象,只需将请求发送到责任链上即可。
灵活动态的处理流程:通过配置责任链,可以灵活地组合处理对象,实现不同的处理流程,并且可以在运行时动态地改变处理的顺序。
增强代码的可扩展性:由于责任链模式遵循开闭原则,新的处理者可以随时被加入到责任链中,不需要修改已有代码,提供了良好的扩展性。
增强代码的可维护性:每个处理者只需关注自己负责处理的请求,职责单一,使得代码更加清晰、可读性更高。

缺点:

请求的处理不保证被处理:由于责任链中的每个处理者都可以选择是否处理请求,如果没有正确配置责任链或者某个处理者没有正确处理请求,可能会导致请求无法被处理。
性能问题:当责任链过长或者请求在责任链中被频繁传递时,可能会对性能产生影响。因此,在设计责任链时需要注意链的长度和处理的复杂度。
调试不方便:当责任链特别是链条比较长, 环节比较多的时候,由于采用了类似递归的方式,调试的时候逻辑可能比较复杂。

3、实现方式


import java.util.*;

public class Test {
    private static AbstractHandler getChainOfHandler() {
        AbstractHandler handler1 = new Handler1();
        AbstractHandler handler2 = new Handler2();
        AbstractHandler handler3 = new Handler3();
        //可以自定义链路顺序
        handler1.setNextChain(handler2).setNextChain(handler3);
        return handler1;
    }

    public static void main(String[] args) {
        AbstractHandler chain = getChainOfHandler();
        LeaveRequest request1 = new LeaveRequest("张三", 2);
        chain.linkChain(request1);

        LeaveRequest request2 = new LeaveRequest("李四", 5);
        chain.linkChain(request2);

        LeaveRequest request3 = new LeaveRequest("王五", 10);
        chain.linkChain(request3);
    }
}


/**
 * <p>
 * 责任链模式——抽象类处理器
 * </p>
 */

public abstract class AbstractHandler {

    /**
     * 责任链中的下一个元素
     */
    protected AbstractHandler nextHandler;

    public AbstractHandler setNextChain(AbstractHandler nextHandler) {
        this.nextHandler = nextHandler;
        return nextHandler;
    }

    /**
     * 责任链处理逻辑
     */
    public void linkChain(LeaveRequest request) {
        handler(request);
        //这里还可以加入其他方法
        if (Objects.nonNull(nextHandler)) {
            nextHandler.linkChain(request);
        }
    }

    /**
     * 抽象方法
     */
    protected abstract void handler(LeaveRequest request);
}


public class LeaveRequest {
    private final String employee;
    private final int days;

    public LeaveRequest(String employee, int days) {
        this.employee = employee;
        this.days = days;
    }

    public String getEmployee() {
    	return this.employee;
    }
    public int getDays() {
    	return this.days;
    }

}

public class Handler1 extends AbstractHandler {

    @Override
    public void handler(LeaveRequest request) {
        if (request.getDays() <= 3) {
            System.out.println("ConcreteHandlerA 处理了 " + request.getEmployee() + " 的请假申请,天数为:" + request.getDays());
        }
    }
}

public class Handler2 extends AbstractHandler {
    @Override
    public void handler(LeaveRequest request) {
        if (request.getDays() > 3 && request.getDays() <= 7) {
            System.out.println("ConcreteHandlerB 处理了 " + request.getEmployee() + " 的请假申请,天数为:" + request.getDays());
        }
    }
}

public class Handler3 extends AbstractHandler {
    @Override
    protected void handler(LeaveRequest request) {
        if (request.getDays() > 7) {
            System.out.println("ConcreteHandlerC 处理了 " + request.getEmployee() + " 的请假申请,天数为:" + request.getDays());
        }
    }
}

4、应用场景

过滤器模式:
例如在Java Web应用中,过滤器链用于对HTTP请求和响应进行处理。每个过滤器负责处理特定的任务,然后将请求传递给下一个过滤器。这种场景下,责任链模式可以有效地解耦每个过滤器的处理逻辑。

事件处理模式:
在图形用户界面编程中,事件处理通常采用责任链模式。例如在一个按钮上,可能有多个监听器(如点击、鼠标移动等),每个监听器负责处理一种特定的事件。当事件发生时,会沿着监听器链进行传递,直到有监听器处理该事件为止。

如日志记录器链:一个日志记录系统可以根据日志级别将日志消息传递给不同的日志记录器,如控制台记录器、文件记录器、数据库记录器等。

工作流引擎:
在企业级应用中,工作流引擎通常使用责任链模式来处理复杂的业务流程。每个处理节点负责处理流程中的特定步骤,然后将工作项传递给下一个处理节点。如审批流程:一个多级审批系统可以根据审批者的权限和级别将审批请求传递给下一个级别的审批者,直到获得最终的审批结果。

权限设计:
在权限设计中,可以使用责任链模式来实现权限验证。例如,一个用户可能需要经过多个角色的权限验证,每个角色负责验证一部分权限。这样既可以实现权限验证的逻辑分离,又可以提高系统的灵活性和扩展性。

This entry was posted in 应用, 设计模式. Bookmark the permalink.