责任链由多个节点(处理器)组成。在行为上有两种

  1. (经典责任链模式)遍历链条上的节点,直到找到对应节点,然后处理为止。(基于数组的遍历)
  2. (变种责任链)由各个节点依次处理,共享负担责任的一部分(通过引用组成链表)

类图

image.png

设计一个缓存模块

方案一

  1. 简单
  2. 耦合性高

方案二

复杂度很高

经典责任链

Trouble

  1. /**
  2. * 问题类
  3. **/
  4. public class Trouble {
  5. private int number;
  6. public Trouble(int number){
  7. this.number=number;
  8. }
  9. public int getNumber() {
  10. return number;
  11. }
  12. @Override
  13. public String toString() {
  14. return "[Trouble "+ number +
  15. ']';
  16. }
  17. }

Support

  1. /**
  2. * @author chenxinwei
  3. * @date 2021/5/17 11:00
  4. **/
  5. public abstract class Support {
  6. private String name;
  7. private Support next;
  8. public Support(String name) {
  9. this.name = name;
  10. }
  11. protected Support setNext(Support next) {
  12. this.next = next;
  13. return next;
  14. }
  15. public Support Support(Support next) {
  16. this.next = next;
  17. return next;
  18. }
  19. public final void support(Trouble trouble) {
  20. if (resolve(trouble)) {
  21. done(trouble);
  22. } else if (next != null) {
  23. next.support(trouble);
  24. } else {
  25. fail(trouble);
  26. }
  27. }
  28. protected abstract boolean resolve(Trouble trouble);
  29. protected void done(Trouble trouble) {
  30. System.out.println(trouble + " is resolved by " + this + " .");
  31. }
  32. protected void fail(Trouble trouble) {
  33. System.out.println(trouble + " cannot be resolved. ");
  34. }
  35. @Override
  36. public String toString() {
  37. return "[" + name + "]";
  38. }
  39. }

LimitSupport

  1. /**
  2. * 解决编号小于limit值的问题
  3. **/
  4. public class LimitSupport extends Support {
  5. private int limit;
  6. public LimitSupport(String name, int limit) {
  7. super(name);
  8. this.limit = limit;
  9. }
  10. @Override
  11. protected boolean resolve(Trouble trouble) {
  12. if (trouble.getNumber() < limit) {
  13. return true;
  14. } else {
  15. return false;
  16. }
  17. }
  18. }

NoSupport

  1. /**
  2. * 永远不解决问题的类
  3. **/
  4. public class NoSupport extends Support{
  5. public NoSupport(String name) {
  6. super(name);
  7. }
  8. @Override
  9. protected boolean resolve(Trouble trouble) {
  10. return false;
  11. }
  12. }

OddSupport

  1. /**
  2. * 解决奇数编号的问题
  3. **/
  4. public class OddSupport extends Support {
  5. public OddSupport(String name) {
  6. super(name);
  7. }
  8. @Override
  9. protected boolean resolve(Trouble trouble) {
  10. if (trouble.getNumber() % 2 == 0) {
  11. return false;
  12. } else {
  13. return true;
  14. }
  15. }
  16. }

SpecialSupport

  1. /**
  2. * 只解决指定编号的问题
  3. **/
  4. public class SpecialSupport extends Support {
  5. private int number;
  6. public SpecialSupport(String name, int number) {
  7. super(name);
  8. this.number = number;
  9. }
  10. @Override
  11. protected boolean resolve(Trouble trouble) {
  12. if (trouble.getNumber() == number) {
  13. return true;
  14. } else {
  15. return false;
  16. }
  17. }
  18. }

类图

LimitSupport.png

解决363号问题的时序图

image.png

责任链中的某一个节点负责处理

image.png

变种责任链

MyBatis缓存使用Cache实现

image.png

链末尾的Cache先执行

image.png

MyBatis调用链

责任链每个点处理一种业务
image.png

练习

基于以下场景设计一个经典的责任链模式

请假审批流程: 1天以内由HR直接审批,2~3天由部门主管审批,三天以上由经理审批。