责任链模式是一种行为型模式。

定义:

  • 使得每一个对象都有机会处理请求,从而避开了请求发送者和请求接受者之间的耦合。
  • 将这些对象连成一条链,沿着这条链传递请求,直到有对象处理为止。

使用场景:

  • 多个对象可以处理同一请求,但具体由哪个对象处理是在运行时动态决定的。
  • 在请求处理者不明确的情况下,向多个对象中的一个提交一个请求。
  • 需要动态指定一组对象处理请求。

链式结构:

  • 具有很强的灵活性,每个节点都可以被拆开再连接。

责任链模式:

  • 将链式结构应用到了编程领域,可将链中的节点看做是一个个对象,每一个对象都有不同的处理逻辑。
  • 当一个请求从链式的首端发出,该请求沿着链的路径依次传递给每一个节点对象,直至有对象处理为止。

示例

小李是某公司的员工,经常因公事出差需要向上级领导报销出差费用。该公司对报销金额的批复权限有着严格的规定,如下:

  • <= 10 元,由员工自行负担。
  • <= 100 元,组长级别即可批复。
  • <= 1000 元,主管级别即可批复。
  • <= 10000 元,经理级别即可批复。
  • <= 100000 元,老板级别即可批复。
  • 其它情况禁止批复,需重新发起报销流程。

首先,不管级别是员工还是其它,我们都可将其抽象一个为 Leader (领导):

  • 每个 Leader 都有一个报销金额的最大值。
  • 除了老板这个 Leader 之外,其余每个 Leader 都会有一个直属的上级领导 nextLeader

    1. public abstract class Leader {
    2. private Leader mNextHandler;
    3. public Leader(Leader nextHandler) {
    4. mNextHandler = nextHandler;
    5. }
    6. // 如果自己能处理该金额,则自己处理,否则需分发给下一级领导进行处理
    7. // 处理成功时,返回 true,否则返回 false
    8. public final boolean dispatchRequest(int money) {
    9. if (money <= getLimit()) {
    10. return handleRequest(money);
    11. }
    12. if (mNextHandler != null) {
    13. return mNextHandler.dispatchRequest(money);
    14. }
    15. return false;
    16. }
    17. public abstract int getLimit();
    18. public abstract boolean handleRequest(int money);
    19. }

    然后,有了抽象 Leader ,我们就可以构建出员工和其它领导了: ```java // 老板 public class Boss extends Leader{ public Boss(Leader nextHandler) {

    1. super(nextHandler);

    }

    @Override public int getLimit() {

    1. return 100000;

    }

    @Override public boolean handleRequest(int money) {

    1. System.out.println("老板批复报销" + money + "元");
    2. return true;

    } }

// 经理 public class Manager extends Leader{

  1. public Manager(Leader nextHandler) {
  2. super(nextHandler);
  3. }
  4. @Override
  5. public int getLimit() {
  6. return 10000;
  7. }
  8. @Override
  9. public boolean handleRequest(int money) {
  10. System.out.println("经理批复报销" + money + "元");
  11. return true;
  12. }

}

// 主管 public class Director extends Leader{ public Director(Leader nextHandler) { super(nextHandler); }

  1. @Override
  2. public int getLimit() {
  3. return 1000;
  4. }
  5. @Override
  6. public boolean handleRequest(int money) {
  7. System.out.println("主管批复报销" + money + "元");
  8. return true;
  9. }

}

// 组长 public class Grouper extends Leader{ public Grouper(Leader nextHandler) { super(nextHandler); }

  1. @Override
  2. public int getLimit() {
  3. return 100;
  4. }
  5. @Override
  6. public boolean handleRequest(int money) {
  7. System.out.println("组长批复报销" + money + "元");
  8. return true;
  9. }

}

// 小李 public class XiaoLi extends Leader{ public XiaoLi(Leader nextHandler) { super(nextHandler); }

  1. @Override
  2. public int getLimit() {
  3. return 10;
  4. }
  5. @Override
  6. public boolean handleRequest(int money) {
  7. System.out.println("小李自行花费" + money + "元");
  8. return true;
  9. }

}

  1. 最后,我们连接好「小李 - 组长 - 主管 - 经理 - 老板」这个链,并测试小李的报销逻辑:
  2. ```java
  3. public static void main(String[] args) {
  4. Leader boss = new Boss(null);
  5. Leader manager = new Manager(boss);
  6. Leader director = new Director(manager);
  7. Leader grouper = new Grouper(director);
  8. Leader xiaoLi = new XiaoLi(grouper);
  9. printRequestState(xiaoLi.dispatchRequest(1)); // 小明上限 10 元
  10. printRequestState(xiaoLi.dispatchRequest(12)); // 组长上限 100 元
  11. printRequestState(xiaoLi.dispatchRequest(230)); // 主管上限 1000 元
  12. printRequestState(xiaoLi.dispatchRequest(3400)); // 经理上限 10000 元
  13. printRequestState(xiaoLi.dispatchRequest(45000)); // 老板上限 100000 元
  14. System.out.println("--------");
  15. printRequestState(xiaoLi.dispatchRequest(560000));
  16. }
  17. private static void printRequestState(boolean isSuccess) {
  18. if (isSuccess) {
  19. System.out.println("* 小李报销成功");
  20. } else {
  21. System.out.println("* 没有人批复,小李报销失败");
  22. }
  23. }

日志输出如下:

  1. 小李自行花费1
  2. * 小李报销成功
  3. 组长批复报销12
  4. * 小李报销成功
  5. 主管批复报销230
  6. * 小李报销成功
  7. 经理批复报销3400
  8. * 小李报销成功
  9. 老板批复报销45000
  10. * 小李报销成功
  11. --------
  12. * 没有人批复,小李报销失败
  • 当小李出差费用为 1 元时,按照公司规定得 自行 处理。
  • 当小李出差费用为 12 元时,按照公司规定可找 组长 批复报销。
  • 当小李出差费用为 230 元时,按照公司规定可找 主管 批复报销。
  • 当小李出差费用为 3400 元时,按照公司规定可找 经理 批复报销。
  • 当小李出差费用为 45000 元时,按照公司规定可找 老板 批复报销。
  • 当小李出差费用为 560000 元时,无人批复,得重新发起报销申请。

示意图如下:
责任链模式 - 图1

假设在小李报销 3400 元过程的过程中,经理休假了,这条链也是能正常工作的 (因为报销申请会传到老板那里,因为 3400 元还是在老板最大批复限额内,所以可有老板批复报销申请)。

总结

责任链模式的优点:

  • 将请求的发送者和接收者进行解耦,降低了耦合度。
  • 对象不需要知道链的结构,简化了对象。
  • 可自由改变链内的成员或者调动它们的次序,或者是动态地新增或者删除责任,增强了给对象指派职责的灵活性。

责任链模式的缺点:

  • 不能保证请求一定被接收。
  • 系统性能可能会受到一定影响,进行代码调试时也不太方便,可能会造成循环调用。
  • 不容易观察出运行时的特征,不利于问题排查。