Chain of Responsibility Pattern

Posted by Dustin Boston in .

The Chain of Responsibility Pattern is a behavioral design pattern that enables a request to be passed along a chain of handlers, allowing for flexible and dynamic processing of requests.


The Chain of Responsibility Pattern is a behavioral design pattern that allows a request to be passed through a chain of handlers until one of them processes it. This approach promotes flexibility by decoupling the sender and receiver, enabling dynamic and customizable request handling. It is particularly useful in scenarios where multiple objects can handle a request, but the specific handler is determined at runtime.

Source Code Listing

code.ts

type Handler = {
  handleRequest(request: string): void; // Pass the request data
  setSuccessor(successor: Handler | undefined): void;
};

class AbstractHandler implements Handler {
  protected successor: Handler | undefined = undefined;

  constructor(protected kind: string) {}

  setSuccessor(successor: Handler | undefined): void {
    this.successor = successor;
  }

  handleRequest(request: string): void {
    if (this.canHandle(request)) {
      this.handle(request);
    } else if (this.successor !== undefined) {
      this.successor.handleRequest(request);
    }
  }

  protected canHandle(_request: string): boolean {
    return true; // Default implementation, subclasses can override
  }

  protected handle(_request: string): void {
    // Subclasses should implement this to define their handling logic
  }
}

class ConcreteHandler1 extends AbstractHandler {
  protected handle(request: string): void {
    console.log(`${this.kind} handled request: ${request}`);
  }
}

class ConcreteHandler2 extends AbstractHandler {
  protected canHandle(request: string): boolean {
    return request.startsWith("prefix_"); // Example condition
  }

  protected handle(request: string): void {
    console.log(`${this.kind} handled request: ${request}`);
  }
}

const client = {
  run(): void {
    const handler1 = new ConcreteHandler1("foo");
    const handler2 = new ConcreteHandler2("bar");

    handler2.setSuccessor(handler1); // Set the chain

    handler2.handleRequest("some_request"); // Will be handled by handler1
    handler2.handleRequest("prefix_another_request"); // Will be handled by handler2
  },
};

client.run();