Bird
Raised Fist0

Chain of Responsibility - Passing Requests Through a Chain of Handlers

LLDmediumInterview freq: medium
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
Handler abstract class

Handler is an abstract class holding a reference to next Handler and shared handle logic.

🎯 Tests whether candidate knows abstract class is used because Handler holds state (next) and partial behavior, which interfaces cannot hold in Java.
public abstract class Handler {
    protected volatile Handler next;
    public synchronized void setNext(Handler next) {
        this.next = next;
    }
    public synchronized void handle(Request request) {
        if (next != null) {
            next.handle(request);
        }
    }
}
ConcreteHandlerA realization

ConcreteHandlerA extends Handler and overrides handle to process or delegate requests.

🎯 Tests Template Method pattern realization and synchronized handle method to avoid race conditions in concurrent chains.
public class ConcreteHandlerA extends Handler {
    @Override
    public synchronized void handle(Request request) {
        if ("TypeA".equals(request.getType())) {
            System.out.println("Handled by A");
        } else {
            super.handle(request);
        }
    }
}
Client association with Handler

Client holds a reference to Handler and sends requests to it, starting the chain.

🎯 Tests association relationship where Client uses Handler but does not own its lifecycle, enforcing single responsibility and OCP.
public class Client {
    private Handler handler;
    public Client(Handler handler) {
        this.handler = handler;
    }
    public void sendRequest(Request request) {
        handler.handle(request);
    }
}
Request class as value object

Request is a simple class holding request data with no behavior, passed along the chain.

🎯 Tests understanding that Request is a value object with independent lifecycle and no concurrency concerns.
public class Request {
    private final String type;
    public Request(String type) {
        this.type = type;
    }
    public String getType() {
        return type;
    }
}
📐
Class Diagram
Class Diagram
       +----------------+
       |    <<Client>>  |
       |    Client      |
       +----------------+
       | - handler:Handler|
       +----------------+
       | + sendRequest(Request):void |
       +----------------+
              │
              │ association (Client uses Handler)
              │
       +----------------+
       |  <<Abstract>>  |
       |    Handler     |
       +----------------+
       | - next:Handler |
       +----------------+
       | + setNext(Handler):void [sync] |
       | + handle(Request):void [sync]  |
       +----------------+
              │ extends
              │
       +----------------+
       | ConcreteHandlerA|
       +----------------+
       | + handle(Request):void [sync]  |
       +----------------+
              │ extends
              │
       +----------------+
       | ConcreteHandlerB|
       +----------------+
       | + handle(Request):void [sync]  |
       +----------------+
       +----------------+
       |    Request     |
       +----------------+
       | - type:String  |
       +----------------+
       | + getType():String |
       +----------------+

This class diagram illustrates the Chain of Responsibility pattern implemented in Java using an abstract Handler class that holds the next handler reference as volatile to ensure visibility across threads. The abstract Handler defines a synchronized handle method implementing the Template Method pattern, allowing concrete handlers like ConcreteHandlerA and ConcreteHandlerB to override request processing while safely delegating to the next handler. The Client class holds an association to Handler, invoking handle to start the chain without owning the handler lifecycle, enforcing single responsibility and open-closed principles. The Request class is a simple immutable value object passed through the chain. Synchronization on handle and setNext methods prevents race conditions during concurrent request processing, ensuring thread-safe chain traversal.

Primary Focus

✓ Abstract class vs Interface + Association lifecycle + Template Method realization + Chain passing concurrency

Practice

(1/5)
1. In the Online Auction System, the AuctionManager class has a private constructor and a static synchronized getInstance() method. Which design pattern is applied here and why is this the correct choice?
easy
A. Singleton pattern, to ensure only one AuctionManager instance manages all auctions globally.
B. Factory pattern, because it controls object creation centrally for different auction types.
C. Builder pattern, to incrementally construct complex AuctionManager configurations.
D. Prototype pattern, to clone AuctionManager instances for each auction session.

Solution

  1. Step 1: Identify Singleton intent

    The private constructor and static synchronized getInstance() method ensure only one instance of AuctionManager exists, centralizing auction state management.
  2. Step 2: Eliminate other patterns

    Factory creates multiple objects, Builder incrementally builds complex objects, Prototype clones instances--none enforce single global instance.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Private constructor + synchronized getInstance() -> Singleton pattern [check]
Hint: Private constructor + static getInstance() -> Singleton [check]
Common Mistakes:
2. In the Jigsaw Puzzle System, the Board class has a placePiece() method that first checks if a position is free and then places the piece. Without synchronizing placePiece(), what exact sequence of thread interleaving causes two threads to place different pieces at the same position (double-booking)?
medium
A. Thread 1 checks position free -> true, context switch; Thread 2 checks position free -> true; both place pieces concurrently.
B. Thread 1 places piece, Thread 2 waits, then places piece after Thread 1 finishes.
C. Thread 1 and Thread 2 both call placePiece() but on different board instances, causing no conflict.
D. Thread 1 locks the board, Thread 2 spins waiting, so no double-booking occurs.

Solution

  1. Step 1: Identify the check-then-act race condition

    Without synchronization, Thread 1 checks position free and sees true, but before placing, context switches.
  2. Step 2: Thread 2 also checks position free -> true and proceeds to place piece concurrently, causing double-booking.

  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized check-then-act allows both threads to place pieces at same position [check]
Hint: Check-then-act without sync -> double-booking race [check]
Common Mistakes:
3. In the playback queue, the method addTrack() is not synchronized. Two threads concurrently check if the queue has space and then add tracks. Which exact sequence causes a race condition leading to queue overflow?
medium
A. Thread 1 checks queue size -> space available, context switch, Thread 2 checks queue size -> space available, both add tracks exceeding capacity.
B. Thread 1 adds a track, Thread 2 waits until Thread 1 finishes, then adds another track safely.
C. Thread 1 locks queue, Thread 2 spins waiting for lock, no race occurs.
D. Thread 1 removes a track while Thread 2 adds, causing inconsistent queue state.

Solution

  1. Step 1: Identify the check-then-act pattern in addTrack()

    Both threads check queue size before adding, but without synchronization, the state can change between check and add.
  2. Step 2: Trace the race condition sequence

    Thread 1 checks size -> space available, context switch before adding. Thread 2 checks size -> space available, both add tracks, causing overflow.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized check-then-act -> double add -> overflow [check]
Hint: Check-then-act without sync -> race condition [check]
Common Mistakes:
4. In a vending machine using the State pattern, if the method selectItem() is not synchronized, which exact thread interleaving causes dispensing the same item twice?
medium
A. Thread 1 checks item availability -> true, context switch, Thread 2 checks availability -> true, both dispense item
B. Thread 1 and Thread 2 both wait on a lock, causing deadlock
C. Thread 1 updates inventory, Thread 2 reads old inventory before update
D. Thread 1 calls selectItem(), Thread 2 calls cancel(), both proceed concurrently

Solution

  1. Step 1: Identify the check-then-act race

    Without synchronization, both threads can read item availability as true before either decrements inventory.
  2. Step 2: Trace the interleaving

    Thread 1 checks availability -> true, context switch; Thread 2 checks availability -> true; both proceed to dispense, causing double dispense.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized check-then-act -> double dispense [check]
Hint: Check-then-act without sync -> double dispense race [check]
Common Mistakes:
5. In a parking lot system, if parkVehicle() is not synchronized, which exact sequence of Thread 1 and Thread 2 causes double-booking of the same spot?
medium
A. Thread 1 checks isAvailable() -> true, context switch; Thread 2 checks isAvailable() -> true; both park the vehicle in the same spot.
B. Thread 1 and Thread 2 both call parkVehicle() simultaneously and crash.
C. Thread 1 parks vehicle, then Thread 2 parks vehicle after spot is freed.
D. Thread 1 calls parkVehicle(), Thread 2 waits until Thread 1 finishes, then parks.

Solution

  1. Step 1: Identify the check-then-act race condition

    Without synchronization, Thread 1 reads spot as available, then context switches before marking it occupied.
  2. Step 2: Trace Thread 2's actions

    Thread 2 also reads spot as available and proceeds to park, causing double-booking.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized check-then-act -> both threads see available -> double-booking [check]
Hint: Check-then-act gap without sync -> double-booking race [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard