# Chain of Responsibility

## Problem

A support ticket system needs to route requests through multiple levels (L1 → L2 → L3 → Manager). Each level can either handle the ticket or escalate it. Hard-coding the routing logic into a single function creates a rigid, unmaintainable chain. Adding or removing a level requires modifying the core logic.

## Solution

Create a chain of handler objects, each with a reference to the next handler. Each handler decides whether to process the request or pass it along. The sender doesn't know (or care) which handler ultimately processes the request.

**Key participants:**
- **Handler** — declares the interface and holds a reference to the next handler
- **ConcreteHandler** — handles requests it's responsible for, forwards the rest
- **Client** — initiates the request to the first handler in the chain

## When to Use

- Multiple objects may handle a request and the handler isn't known in advance
- You want to decouple the sender from the receiver
- The set of handlers or their order should be configurable at runtime
- A request should be processed by exactly one handler in a prioritized chain

## When to Avoid

- Every request must be handled (chain may silently drop requests if no handler matches)
- You need guaranteed delivery — use a direct dispatch or Command pattern instead
- The chain is only one handler deep — unnecessary abstraction
- Performance is critical and the chain is very long

## Pseudocode

```
INTERFACE Handler:
    method set_next(handler: Handler) -> Handler
    method handle(request) -> string or null

CLASS BaseHandler IMPLEMENTS Handler:
    next_handler = null

    method set_next(handler):
        next_handler = handler
        RETURN handler  // enables chaining

    method handle(request):
        IF next_handler IS NOT null:
            RETURN next_handler.handle(request)
        RETURN null  // end of chain, unhandled

CLASS L1Support EXTENDS BaseHandler:
    method handle(request):
        IF request.severity <= 1:
            RETURN "L1 handled: " + request.description
        RETURN super.handle(request)

// Build chain: l1 -> l2 -> l3 -> manager
l1.set_next(l2).set_next(l3).set_next(manager)
result = l1.handle(ticket)
```

## Python

```python
from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass


@dataclass
class Ticket:
    description: str
    severity: int  # 1=low, 2=medium, 3=high, 4=critical


class Handler(ABC):
    def __init__(self) -> None:
        self._next: Handler | None = None

    def set_next(self, handler: Handler) -> Handler:
        self._next = handler
        return handler

    @abstractmethod
    def handle(self, ticket: Ticket) -> str | None:
        pass

    def pass_to_next(self, ticket: Ticket) -> str | None:
        if self._next:
            return self._next.handle(ticket)
        return None


class L1Support(Handler):
    def handle(self, ticket: Ticket) -> str | None:
        if ticket.severity <= 1:
            return f"L1 resolved: {ticket.description}"
        print(f"  L1 cannot handle severity {ticket.severity}, escalating...")
        return self.pass_to_next(ticket)


class L2Support(Handler):
    def handle(self, ticket: Ticket) -> str | None:
        if ticket.severity <= 2:
            return f"L2 resolved: {ticket.description}"
        print(f"  L2 cannot handle severity {ticket.severity}, escalating...")
        return self.pass_to_next(ticket)


class L3Support(Handler):
    def handle(self, ticket: Ticket) -> str | None:
        if ticket.severity <= 3:
            return f"L3 resolved: {ticket.description}"
        print(f"  L3 cannot handle severity {ticket.severity}, escalating...")
        return self.pass_to_next(ticket)


class Manager(Handler):
    def handle(self, ticket: Ticket) -> str | None:
        return f"Manager resolved: {ticket.description}"


def main() -> None:
    # Build chain
    l1 = L1Support()
    l2 = L2Support()
    l3 = L3Support()
    manager = Manager()
    l1.set_next(l2).set_next(l3).set_next(manager)

    tickets = [
        Ticket("Password reset", 1),
        Ticket("Software installation", 2),
        Ticket("Server outage", 3),
        Ticket("Data breach detected", 4),
    ]

    for ticket in tickets:
        print(f"\nTicket: {ticket.description} (severity={ticket.severity})")
        result = l1.handle(ticket)
        print(f"  Result: {result}")


if __name__ == "__main__":
    main()
```

**Output:**
```
Ticket: Password reset (severity=1)
  Result: L1 resolved: Password reset

Ticket: Software installation (severity=2)
  L1 cannot handle severity 2, escalating...
  Result: L2 resolved: Software installation

Ticket: Server outage (severity=3)
  L1 cannot handle severity 3, escalating...
  L2 cannot handle severity 3, escalating...
  Result: L3 resolved: Server outage

Ticket: Data breach detected (severity=4)
  L1 cannot handle severity 4, escalating...
  L2 cannot handle severity 4, escalating...
  L3 cannot handle severity 4, escalating...
  Result: Manager resolved: Data breach detected
```

## Go

```go
package main

import "fmt"

type Ticket struct {
	Description string
	Severity    int
}

type Handler interface {
	SetNext(handler Handler) Handler
	Handle(ticket Ticket) string
}

type BaseHandler struct {
	next Handler
}

func (b *BaseHandler) SetNext(handler Handler) Handler {
	b.next = handler
	return handler
}

func (b *BaseHandler) passToNext(ticket Ticket) string {
	if b.next != nil {
		return b.next.Handle(ticket)
	}
	return "No handler available"
}

// L1Support handles severity <= 1
type L1Support struct{ BaseHandler }

func (h *L1Support) Handle(ticket Ticket) string {
	if ticket.Severity <= 1 {
		return fmt.Sprintf("L1 resolved: %s", ticket.Description)
	}
	fmt.Printf("  L1 cannot handle severity %d, escalating...\n", ticket.Severity)
	return h.passToNext(ticket)
}

// L2Support handles severity <= 2
type L2Support struct{ BaseHandler }

func (h *L2Support) Handle(ticket Ticket) string {
	if ticket.Severity <= 2 {
		return fmt.Sprintf("L2 resolved: %s", ticket.Description)
	}
	fmt.Printf("  L2 cannot handle severity %d, escalating...\n", ticket.Severity)
	return h.passToNext(ticket)
}

// L3Support handles severity <= 3
type L3Support struct{ BaseHandler }

func (h *L3Support) Handle(ticket Ticket) string {
	if ticket.Severity <= 3 {
		return fmt.Sprintf("L3 resolved: %s", ticket.Description)
	}
	fmt.Printf("  L3 cannot handle severity %d, escalating...\n", ticket.Severity)
	return h.passToNext(ticket)
}

// Manager handles everything
type Manager struct{ BaseHandler }

func (h *Manager) Handle(ticket Ticket) string {
	return fmt.Sprintf("Manager resolved: %s", ticket.Description)
}

func main() {
	l1 := &L1Support{}
	l2 := &L2Support{}
	l3 := &L3Support{}
	mgr := &Manager{}

	l1.SetNext(l2).SetNext(l3).SetNext(mgr)

	tickets := []Ticket{
		{"Password reset", 1},
		{"Software installation", 2},
		{"Server outage", 3},
		{"Data breach detected", 4},
	}

	for _, t := range tickets {
		fmt.Printf("\nTicket: %s (severity=%d)\n", t.Description, t.Severity)
		result := l1.Handle(t)
		fmt.Printf("  Result: %s\n", result)
	}
}
```

**Output:**
```
Ticket: Password reset (severity=1)
  Result: L1 resolved: Password reset

Ticket: Software installation (severity=2)
  L1 cannot handle severity 2, escalating...
  Result: L2 resolved: Software installation

Ticket: Server outage (severity=3)
  L1 cannot handle severity 3, escalating...
  L2 cannot handle severity 3, escalating...
  Result: L3 resolved: Server outage

Ticket: Data breach detected (severity=4)
  L1 cannot handle severity 4, escalating...
  L2 cannot handle severity 4, escalating...
  L3 cannot handle severity 4, escalating...
  Result: Manager resolved: Data breach detected
```

## JavaScript

```javascript
class Ticket {
  constructor(description, severity) {
    this.description = description;
    this.severity = severity;
  }
}

class Handler {
  constructor() {
    this.next = null;
  }

  setNext(handler) {
    this.next = handler;
    return handler;
  }

  handle(ticket) {
    if (this.next) {
      return this.next.handle(ticket);
    }
    return "No handler available";
  }
}

class L1Support extends Handler {
  handle(ticket) {
    if (ticket.severity <= 1) {
      return `L1 resolved: ${ticket.description}`;
    }
    console.log(`  L1 cannot handle severity ${ticket.severity}, escalating...`);
    return super.handle(ticket);
  }
}

class L2Support extends Handler {
  handle(ticket) {
    if (ticket.severity <= 2) {
      return `L2 resolved: ${ticket.description}`;
    }
    console.log(`  L2 cannot handle severity ${ticket.severity}, escalating...`);
    return super.handle(ticket);
  }
}

class L3Support extends Handler {
  handle(ticket) {
    if (ticket.severity <= 3) {
      return `L3 resolved: ${ticket.description}`;
    }
    console.log(`  L3 cannot handle severity ${ticket.severity}, escalating...`);
    return super.handle(ticket);
  }
}

class ManagerHandler extends Handler {
  handle(ticket) {
    return `Manager resolved: ${ticket.description}`;
  }
}

// Build chain
const l1 = new L1Support();
const l2 = new L2Support();
const l3 = new L3Support();
const manager = new ManagerHandler();
l1.setNext(l2).setNext(l3).setNext(manager);

const tickets = [
  new Ticket("Password reset", 1),
  new Ticket("Software installation", 2),
  new Ticket("Server outage", 3),
  new Ticket("Data breach detected", 4),
];

for (const ticket of tickets) {
  console.log(`\nTicket: ${ticket.description} (severity=${ticket.severity})`);
  const result = l1.handle(ticket);
  console.log(`  Result: ${result}`);
}
```

**Output:**
```
Ticket: Password reset (severity=1)
  Result: L1 resolved: Password reset

Ticket: Software installation (severity=2)
  L1 cannot handle severity 2, escalating...
  Result: L2 resolved: Software installation

Ticket: Server outage (severity=3)
  L1 cannot handle severity 3, escalating...
  L2 cannot handle severity 3, escalating...
  Result: L3 resolved: Server outage

Ticket: Data breach detected (severity=4)
  L1 cannot handle severity 4, escalating...
  L2 cannot handle severity 4, escalating...
  L3 cannot handle severity 4, escalating...
  Result: Manager resolved: Data breach detected
```

## Related Patterns

- **Decorator** — Both chain wrappers around an object. Decorator always forwards; Chain of Responsibility may stop at any handler.
- **Command** — Each handler in the chain often executes a Command.
- **Composite** — Chain nodes can be Composite nodes that delegate to sub-handlers.
- **Strategy** — Each handler can use a Strategy for its decision logic.
- **Observer** — Chain handlers can emit events on success/failure via Observer.
- **Pipe and Filter** — A Pipe and Filter is a Chain of Responsibility where every handler always passes to the next (no early termination).
