The Chain of Responsibility (COR) is a pattern that allows some request to be sent, received, and handled by multiple objects. These objects (which are just functions) are not dependent on the implementation details of the previous nor the next request and can decide what to do when it runs its execution. They can also either abort the whole chain or decide to let the request continue on to the next object (or function) in the chain.

没有用责任链时

  1. const httpErrorHandler = (error) => {
  2. const errorStatus = error.response.status;
  3. if (errorStatus === 400) {
  4. console.log('安安,你是不是給了我奇怪的東西?');
  5. }
  6. if (errorStatus === 401) {
  7. console.log('先登入行不?');
  8. }
  9. if (errorStatus === 403) {
  10. console.log('想偷幹壞事?');
  11. }
  12. if (errorStatus === 404) {
  13. console.log('這裡什麼都沒有(雙手一攤');
  14. }
  15. };

使用责任链

  1. 当前的执行者
  2. 下一个执行者
  3. 判断当前执行者执行后是否需要交给下一个接收者

    1. class Chain {
    2. constructor(handler) {
    3. this.handler = handler;
    4. this.successor = null;
    5. }
    6. setSuccessor(successor) {
    7. this.successor = successor;
    8. return this;
    9. }
    10. passRequest(...args) {
    11. const result = this.handler(...args);
    12. if (result === 'next') {
    13. return this.successor && this.successor.passRequest(...args);
    14. }
    15. return result;
    16. }
    17. }

    ```typescript const response400 = (error) => { if (error.response.status !== 400) return ‘next’; console.log(‘安安,你是不是給了我奇怪的東西?’); };

const response401 = (error) => { if (error.response.status !== 401) return ‘next’; console.log(‘先登入行不?’); };

const response403 = (error) => { if (error.response.status !== 403) return ‘next’;; console.log(‘想偷幹壞事?’); };

const response404 = (error) => { if (error.response.status !== 404) return ‘next’;; console.log(‘這裡什麼都沒有(雙手一攤’); };

const httpErrorHandler = (error) => { const chainRequest400 = new Chain(response400); const chainRequest401 = new Chain(response401); const chainRequest403 = new Chain(response403); const chainRequest404 = new Chain(response404);

chainRequest400.setSuccessor(chainRequest401); chainRequest401.setSuccessor(chainRequest403); chainRequest403.setSuccessor(chainRequest404);

chainRequest400.passRequest(error); };

  1. ts 实现
  2. ```javascript
  3. /**
  4. * The Handler interface declares a method for building the chain of handlers.
  5. * It also declares a method for executing a request.
  6. */
  7. interface Handler {
  8. setNext(handler: Handler): Handler;
  9. handle(request: string): string;
  10. }
  11. /**
  12. * The default chaining behavior can be implemented inside a base handler class.
  13. */
  14. abstract class AbstractHandler implements Handler
  15. {
  16. private nextHandler: Handler;
  17. public setNext(handler: Handler): Handler {
  18. this.nextHandler = handler;
  19. // Returning a handler from here will let us link handlers in a
  20. // convenient way like this:
  21. // monkey.setNext(squirrel).setNext(dog);
  22. return handler;
  23. }
  24. public handle(request: string): string {
  25. if (this.nextHandler) {
  26. return this.nextHandler.handle(request);
  27. }
  28. return null;
  29. }
  30. }
  31. /**
  32. * All Concrete Handlers either handle a request or pass it to the next handler
  33. * in the chain.
  34. */
  35. class MonkeyHandler extends AbstractHandler {
  36. public handle(request: string): string {
  37. if (request === 'Banana') {
  38. return `Monkey: I'll eat the ${request}.`;
  39. }
  40. return super.handle(request);
  41. }
  42. }
  43. class SquirrelHandler extends AbstractHandler {
  44. public handle(request: string): string {
  45. if (request === 'Nut') {
  46. return `Squirrel: I'll eat the ${request}.`;
  47. }
  48. return super.handle(request);
  49. }
  50. }
  51. class DogHandler extends AbstractHandler {
  52. public handle(request: string): string {
  53. if (request === 'MeatBall') {
  54. return `Dog: I'll eat the ${request}.`;
  55. }
  56. return super.handle(request);
  57. }
  58. }
  59. /**
  60. * The client code is usually suited to work with a single handler. In most
  61. * cases, it is not even aware that the handler is part of a chain.
  62. */
  63. function clientCode(handler: Handler) {
  64. const foods = ['Nut', 'Banana', 'Cup of coffee'];
  65. for (const food of foods) {
  66. console.log(`Client: Who wants a ${food}?`);
  67. const result = handler.handle(food);
  68. if (result) {
  69. console.log(` ${result}`);
  70. } else {
  71. console.log(` ${food} was left untouched.`);
  72. }
  73. }
  74. }
  75. /**
  76. * The other part of the client code constructs the actual chain.
  77. */
  78. const monkey = new MonkeyHandler();
  79. const squirrel = new SquirrelHandler();
  80. const dog = new DogHandler();
  81. monkey.setNext(squirrel).setNext(dog);
  82. /**
  83. * The client should be able to send a request to any handler, not just the
  84. * first one in the chain.
  85. */
  86. console.log('Chain: Monkey > Squirrel > Dog\n');
  87. clientCode(monkey);
  88. console.log('');
  89. console.log('Subchain: Squirrel > Dog\n');
  90. clientCode(squirrel);

使用场景

  • 过滤器
  • 拦截器

    参考资料

  1. The Power of Chain Of Responsibility in JavaScript
  2. 用 JavaScript 玩轉設計模式 | 各司其職的 Chain of Responsibility Pattern
  3. 179.精读《设计模式 - Chain of Responsibility 职责链模式》.md
  4. Solving Complex Filters with the Chain of Responsibility Design Pattern in JavaScript
  5. 责任链模式