设计模式 - 责任链模式

132 阅读6分钟

设计模式 - 责任链模式

一、引入

当你在公司里提交了一份请假申请时,通常会经历一些审批环节,比如先交给你的直属领导审批,如果他没意见,就会交给部门经理,接着是总经理,最后是人事部。

责任链模式就像这样一个审批流程。它是一种设计模式,用于处理一个请求可能由多个处理者来处理的情况。

在责任链模式中,每个处理者都有一个确定的责任范围,只有当自己能够处理请求时,才会进行处理,否则会将请求传递给下一个处理者。这样一直传递下去,直到有一个处理者能够处理该请求或者所有的处理者都不能处理为止。

举例来说,比如一个在线购物系统,当你下单后,订单会经过多个处理者的处理,比如库存检查、价格计算、支付处理等等,每个处理者只负责自己擅长的部分,如果自己不能处理,就将订单传递给下一个处理者。

这样做的好处是,系统更加灵活和可扩展,可以动态地调整处理者的顺序或者增加新的处理者,而不需要修改已有的代码。

责任链模式就像一个“处理链”,每个环节只负责处理自己擅长的事情,如果自己不能处理,就传给下一个环节。这样让整个处理过程更加灵活和高效。

二、概念

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它通过一条链来传递请求,直到有一个处理者能够处理该请求为止。

在责任链模式中,通常会有多个处理者(Handler)组成一个链,每个处理者都有一个指向下一个处理者的引用。当一个请求到达时,它会从链的头部开始传递,直到有一个处理者能够处理该请求,或者链的尽头没有能够处理请求的处理者。

三、基本结构

  • 抽象处理者(Handler):定义了处理请求的接口,通常包括一个处理方法以及一个指向下一个处理者的引用。
  • 具体处理者(Concrete Handler):实现了抽象处理者接口,负责处理具体的请求。如果它能够处理请求,则进行处理;如果不能处理,则将请求传递给下一个处理者。
  • 客户端(Client):创建处理链,并向链的头部发送请求。

四、示例代码

/**
 * 请求类
 */
public class Request {
    private String content;

    public Request(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }
}
// 处理者接口
interface Handler {
    void handleRequest(Request request);
}
//具体处理者A
public class ConcreteHandlerA implements Handler {

    private Handler nextHandler;

    @Override
    public void handleRequest(Request request) {
        if (request.getContent().contains("A")) {
            System.out.println("A处理了请求");
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }

    @Override
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }
}

//具体处理者B
public class ConcreteHandlerB implements Handler {
    private Handler nextHandler;

    @Override
    public void handleRequest(Request request) {
        if (request.getContent().contains("B")) {
            System.out.println("B处理了请求");
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }

    @Override
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }
}

//具体处理者C
public class ConcreteHandlerC implements Handler {
    private Handler nextHandler;

    @Override
    public void handleRequest(Request request) {
        if (request.getContent().contains("C")) {
            System.out.println("C处理了请求");
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }

    @Override
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        Handler handlerC = new ConcreteHandlerC();

        handlerA.setNextHandler(handlerB);
        handlerB.setNextHandler(handlerC);

        Request request1 = new Request("Request with A");
        Request request2 = new Request("Request with B");
        Request request3 = new Request("Request with C");

        handlerA.handleRequest(request1);
        handlerA.handleRequest(request2);
        handlerA.handleRequest(request3);
    }
}

五、用途

  1. 请求处理链:当一个请求需要经过多个处理环节,每个环节可能由不同的处理者来处理,责任链模式可以将请求依次传递给各个处理者,直到找到能够处理请求的处理者为止。

  2. 权限校验:在一个系统中,不同用户可能具有不同的权限,需要进行权限校验。责任链模式可以通过一条权限校验链,依次检查用户的权限,如果满足则允许访问,否则拒绝访问。

  3. 日志记录:在系统中需要记录日志,可以通过责任链模式来实现日志记录的功能。不同的处理者负责记录不同级别的日志,比如错误日志、警告日志等。

  4. 过滤器:在Web开发中,经常需要对请求进行过滤,比如输入参数的校验、敏感词过滤等。责任链模式可以将多个过滤器组合成一个过滤链,依次对请求进行过滤。

  5. 缓存处理:在系统中可能需要进行缓存处理,可以通过责任链模式来实现多级缓存的管理,每个处理者负责一个级别的缓存,如果本级缓存没有命中,则传递给下一级缓存。

  6. 异常处理:在系统中可能会有多个异常处理策略,责任链模式可以将异常依次传递给各个处理者,直到找到能够处理该异常的处理者。

  7. 消息通知:在系统中可能需要进行消息通知,比如邮件通知、短信通知等,可以通过责任链模式将消息依次传递给各个通知处理者。

  8. 事件处理:在事件驱动的程序中,可能会有多个事件处理器,责任链模式可以将事件依次传递给各个处理器。

六、总结

优点:

  1. 降低耦合度: 责任链模式将请求和处理者解耦,每个处理者只需要关心自己能否处理该请求,不需要知道整个处理流程的细节。
  2. 灵活性: 可以动态地添加、删除或者改变处理者的顺序,使得系统更加灵活和可扩展。
  3. 单一职责原则: 每个具体处理者只需要关心自己能否处理请求,符合单一职责原则。
  4. 可以避免请求的发送者和接收者之间的直接耦合关系: 发送者只需要知道链的入口,不需要知道链中具体的处理者。
  5. 可以实现请求的动态分配: 根据实际情况,可以动态地决定请求由哪个处理者来处理。

缺点:

  1. 请求处理不保证成功: 因为请求可能会到达链的末端,如果没有处理者能够处理该请求,那么请求将无法得到处理。
  2. 性能问题: 如果责任链比较长,可能会影响系统的性能,因为请求需要依次传递给每个处理者,直到找到能够处理的处理者。
  3. 调试和定位问题: 在责任链模式中,如果出现问题,可能需要跟踪整个链条来定位问题所在,可能会增加调试的难度。
  4. 可能导致循环调用: 如果责任链设计不合理,可能会导致请求在链中循环调用,造成系统崩溃。

总的来说,责任链模式在需要动态地组织处理者并将请求传递给合适的处理者时非常有用,但需要谨慎设计以避免性能问题和循环调用等风险。