GAZAR

Principal Engineer | Mentor

Chain of Responsibility Design Pattern

Chain of Responsibility Design Pattern

At its core, the Chain of Responsibility Pattern consists of two main components: the Handler and the Concrete Handlers. The Handler defines an interface for handling requests and optionally defines a successor to pass the request along the chain. Concrete Handlers implement the Handler interface and specify how they handle the request or pass it to the next handler in the chain. This pattern allows for the decoupling of sender and receiver, enabling multiple objects to handle requests in a flexible and dynamic manner.

// Handler
class SupportAgent {
  constructor(name, nextAgent = null) {
    this.name = name;
    this.nextAgent = nextAgent;
  }

  handleRequest(ticket) {
    if (this.canHandle(ticket)) {
      console.log(`${this.name} is handling ticket: ${ticket}`);
    } else if (this.nextAgent) {
      console.log(`${this.name} cannot handle ticket, passing to ${this.nextAgent.name}`);
      this.nextAgent.handleRequest(ticket);
    } else {
      console.log(`No support agent available to handle ticket: ${ticket}`);
    }
  }

  canHandle(ticket) {
    // Concrete handlers implement this method to determine if they can handle the ticket
    return false;
  }
}

// Concrete Handlers
class LevelOneSupport extends SupportAgent {
  canHandle(ticket) {
    return ticket.level === 1;
  }
}

class LevelTwoSupport extends SupportAgent {
  canHandle(ticket) {
    return ticket.level === 2;
  }
}

class LevelThreeSupport extends SupportAgent {
  canHandle(ticket) {
    return ticket.level === 3;
  }
}

// Usage
const agent1 = new LevelOneSupport("Alice");
const agent2 = new LevelTwoSupport("Bob", agent1);
const agent3 = new LevelThreeSupport("Charlie", agent2);

const ticket1 = { level: 2, description: "Internet connectivity issue" };
const ticket2 = { level: 3, description: "Server outage" };
const ticket3 = { level: 1, description: "Printer malfunction" };

agent3.handleRequest(ticket1);
agent3.handleRequest(ticket2);
agent3.handleRequest(ticket3);

The Chain of Responsibility Pattern provides an elegant solution for handling requests dynamically without tightly coupling the sender to the receiver. By creating a chain of handler objects and allowing each handler to either process the request or pass it to the next handler, this pattern promotes flexibility and extensibility in software systems. In JavaScript, the Chain of Responsibility pattern is commonly used in scenarios such as event handling, middleware pipelines, and error handling.