Skip to main content

🧩 Chain of Responsibility Pattern

βœ… Intent​

  • Chain multiple handler classes together and delegate processing based on conditions
  • Each handler either processes the request or passes it along

βœ… Motivation​

  • Convert branching logic into a sequential processing chain
  • Ideal for situations where the processing flow should be traced step by step

βœ… When to Use​

  • When each handler is independent and only one of them should process the request
  • When you want to delegate to the one matching condition among many

βœ… Code Example​

// ハンドラむンターフェース
interface DiscountHandler {
setNext(handler: DiscountHandler): DiscountHandler;
handle(userType: string, basePrice: number): number;
}

// ζŠ½θ±‘γ‚―γƒ©γ‚ΉοΌˆε…±ι€šε‡¦η†οΌ‰
abstract class BaseDiscountHandler implements DiscountHandler {
private nextHandler: DiscountHandler | null = null;

setNext(handler: DiscountHandler): DiscountHandler {
this.nextHandler = handler;
return handler;
}

handle(userType: string, basePrice: number): number {
if (this.nextHandler) {
return this.nextHandler.handle(userType, basePrice);
}
return basePrice;
}
}

// 各ハンドラ
class StudentHandler extends BaseDiscountHandler {
handle(userType: string, basePrice: number): number {
if (userType === "student") return basePrice * 0.8;
return super.handle(userType, basePrice);
}
}

class MemberHandler extends BaseDiscountHandler {
handle(userType: string, basePrice: number): number {
if (userType === "member") return basePrice * 0.9;
return super.handle(userType, basePrice);
}
}

class VIPHandler extends BaseDiscountHandler {
handle(userType: string, basePrice: number): number {
if (userType === "vip") return basePrice * 0.7;
return super.handle(userType, basePrice);
}
}

// εˆ©η”¨δΎ‹
const student = new StudentHandler();
const member = new MemberHandler();
const vip = new VIPHandler();

student.setNext(member).setNext(vip);

console.log(student.handle("vip", 1000)); // 700
console.log(student.handle("student", 1000)); // 800
console.log(student.handle("guest", 1000)); // 1000

βœ… Explanation​

This code applies the Chain of Responsibility (CoR) pattern to divide discount logic into a series of handlers that process the request sequentially.
The CoR pattern allows multiple objects to process a request in turn, passing it along the chain until an appropriate handler takes responsibility.

1. Overview of the Chain of Responsibility Pattern​

  • Handler: Defines the interface for handling requests

    • Represented by DiscountHandler in this code
  • ConcreteHandler: Implements the Handler interface and handles specific types of requests

    • Implemented by StudentHandler, MemberHandler, and VIPHandler
  • Client: Builds the chain of handlers and passes the request to the first one

    • Represented by student.setNext(member).setNext(vip) in this code

2. Key Classes and Their Roles​

  • DiscountHandler

    • Common interface for all handlers
    • setNext(handler: DiscountHandler): DiscountHandler sets the next handler
    • handle(userType: string, basePrice: number): number processes the request
  • BaseDiscountHandler

    • Abstract class implementing DiscountHandler
    • Provides a default implementation of setNext and delegates to the next handler in handle
  • StudentHandler, MemberHandler, VIPHandler

    • Concrete handler classes extending BaseDiscountHandler
    • Each implements specific discount logic based on user type (student, member, vip)
  • Client Code

    • Constructs the handler chain and sends the request to the first handler

3. UML Class Diagram​

4. Benefits of the Chain of Responsibility Pattern​

  • Flexible Processing Flow: The order of handlers can be changed dynamically
  • Single Responsibility Principle: Each handler is responsible for only one kind of processing
  • Extensibility: New handlers can be added without modifying existing code

This design enables flexible request handling and eliminates complex conditional logic. It is especially effective when processing needs to be dynamically restructured or when multiple conditional branches must be managed cleanly.