Mastering the Chain of Responsibility Pattern: From Classic Story to Front‑End Code

This article explains the Chain of Responsibility design pattern, illustrates it with a historical Three Kingdoms story, shows progressive refactorings from procedural code to abstract handlers in TypeScript, and demonstrates practical front‑end scenarios such as flexible location retrieval.

Huolala Tech
Huolala Tech
Huolala Tech
Mastering the Chain of Responsibility Pattern: From Classic Story to Front‑End Code

Overview

Explain what the Chain of Responsibility pattern is and the problem it solves.

Introduce a short story, code it, and iteratively apply the pattern.

Present a real front‑end business requirement and implement it using the pattern.

What Is the Chain of Responsibility Pattern?

According to the classic Design Patterns: Elements of Reusable Object‑Oriented Software , the pattern allows multiple objects a chance to handle a request, avoiding tight coupling between sender and receiver by linking the objects into a chain and passing the request along until one handles it.

Multiple objects get the opportunity to process a request, thereby decoupling the sender from the receiver; the objects are linked in a chain and the request travels along the chain until an object handles it.

Three Kingdoms Story: Warm‑Wine Slaying Hua Xiong

The well‑known tale of "Warm‑Wine Slaying Hua Xiong" is used as a narrative backdrop.

In the initial procedural version (v1), the code uses nested if statements to simulate each general fighting Hua Xiong:

// Note: naming with pinyin is for demo only; avoid in real projects
function killHuaXiong() {
  let win = false;
  // round 1: General A vs Hua Xiong
  win = APKHuaXiong();
  if (!win) {
    // round 2: General B vs Hua Xiong
    win = BPKHuaXiong();
    if (!win) {
      // round 3: General C vs Hua Xiong
      win = CPKHuaXiong();

      if (!win) {
        // round 4: Guan Yu vs Hua Xiong
        win = DPKHuaXiong();
      }
    }
  }
  return win;
}

Problems with this approach:

Q1: If Guan Yu also loses, the function must be heavily modified—poor extensibility.

Q2: Changing the order of generals requires major rewrites.

Refactoring with the Chain of Responsibility (v2)

The code is restructured using an abstract handler interface and concrete handlers:

abstract class IHandler {
  protected nextHandler: IHandler | null;
  setNextHandler(handler: IHandler): void {
    this.nextHandler = handler;
  }
  abstract handle(): boolean;
}

class AHandler extends IHandler {
  override handle() {
    let canHandle = false;
    console.log('A loses');
    if (!canHandle && this.nextHandler) {
      return this.nextHandler.handle();
    }
    return canHandle;
  }
}

class GuanYuHandler extends IHandler {
  override handle() {
    let canHandle = false;
    console.log('Guan Yu wins');
    // Guan Yu can handle Hua Xiong
    canHandle = true;
    if (!canHandle && this.nextHandler) {
      return this.nextHandler.handle();
    }
    return canHandle;
  }
}

const aHandlerIns = new AHandler();
// similarly create B, C, GuanYu handlers
// chain them
aHandlerIns.setNextHandler(bHandlerIns);
bHandlerIns.setNextHandler(cHandlerIns);
cHandlerIns.setNextHandler(guanYuHandlerIns);
// start the chain
aHandlerIns.handle();

This version solves the earlier issues: adding a new handler only requires creating a class and linking it, while reordering handlers only changes the chain configuration.

Further Abstraction (v3)

Common logic is moved to the abstract base class, leaving only the specific handling in subclasses:

abstract class IHandler {
  // common code lifted to abstract base class
  handle(): boolean {
    const canHandle = this.doHandle();
    if (!canHandle && this.nextHandler) {
      return this.nextHandler.handle();
    }
    return canHandle;
  }
  abstract doHandle(): boolean;
}

class AHandler extends IHandler {
  override doHandle(): boolean {}
}

A manager class could further orchestrate handler ordering, eliminating direct coupling between handlers.

Re‑examining the Definition

The pattern focuses on being able to handle a problem rather than which object ultimately does it.

Knowledge Transfer – Analogy to Linked Lists

The pattern resembles a linked list: Handler is analogous to a Node. nextHandler corresponds to the next pointer.

Front‑End Application Scenarios

In typical front‑end projects, obtaining geographic location can be done via multiple strategies (URL parameters, cached localStorage data, app‑specific APIs, WeChat SDK, Baidu SDK, etc.). The requirement is satisfied as soon as any strategy succeeds, making the Chain of Responsibility a natural fit.

URL parameters: /path?lat=110&lon=123 (app environment)

Valid cached latitude/longitude in localStorage

App‑specific location capability (app environment)

WeChat SDK wx.getLocation (WeChat environment)

Baidu SDK

These handlers are linked into a chain that stops when one returns a location.

Sample TypeScript implementation:

abstract class ILocationHandler {
  async handle(): Promise<Partial<TResult>> {}
  // Some methods can only be used in specific environments, e.g., app's position action
  abstract canIUse(): boolean;
  abstract doHandle(): Promise<Partial<TResult>>;
}

class UrlParamsLocationHandler extends ILocationHandler {
  override canIUse() { return true; }
  override doHandle() { return mockUrlParamsResolver(); // actual location fetch
  }
}

// LocationChain is a linked list of ILocationHandler instances
class LocationChain {
  // ...
  append(handler: ILocationHandler) {}
  async execute() {}
}

Full source code is linked in the references.

Final Thoughts

Many developers lack a solid grasp of OOP concepts. Applying well‑known design patterns like the Chain of Responsibility in appropriate business and engineering contexts leads to more extensible and maintainable code.

References

[1]

Design Patterns: Elements of Reusable Object‑Oriented Software – https://book.douban.com/subject/1436745/ [2] Full code repository – https://codesandbox.io/s/trusting-engelbart-293wzc?file=/src/index.ts

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Chain of ResponsibilitySoftware Architecturedesign patternOOP
Huolala Tech
Written by

Huolala Tech

Technology reshapes logistics

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.