Behavioral · Gang of Four
Chain of Responsibility
Chain of Responsibility is a behavioral pattern that passes a request along a list of handlers. Each handler either handles the request or forwards it. The caller does not know which handler will answer.
Example: an ATM withdrawal needs several checks — card valid, PIN correct, balance enough, fraud screen. A 200-line withdraw() with nested ifs is hard to extend. A chain of handlers keeps each check in its own class.
The interview question
Can I add or reorder a check without opening the 200-line method?
- 1Name the request (Withdrawal).
- 2Give every handler the same door.
- 3Link with setNext, not concrete names.
- 4Stop on failure; cash moves last.
Request walk
The line, left to right
Client talks to Auth. Auth talks to Balance. Balance talks to Limit. Limit talks to Fraud. Nobody in the ATM class names FraudHandler. That is the point: a new KYC check is a new class plus one .
Auth
reject if card is fake
PIN
reject if PIN is wrong
Balance
reject if funds are short
Fraud
stop if the pattern looks stolen
Dispense
only if the line said yes
What happens on a bad PIN
The walk is allowed to die early. That is how a chain differs from a of validators that all run, and from Decorator, where every wrapper still does the call and adds something.
Read the diagram definition
sequenceDiagram
participant ATM as ATM
participant A as Auth
participant B as Balance
participant L as Limit
participant F as Fraud
ATM->>A: handle(withdrawal)
alt card invalid
A-->>ATM: Unauthorized
else card ok
A->>B: handle
alt funds short
B-->>ATM: InsufficientFunds
else funds ok
B->>L: handle
L->>F: handle
F-->>ATM: ok, dispense
end
endChain
Who should answer?
A member may swallow the request. Auth fails, fraud never runs. Use this for ATM checks, support-ticket routing, and HTTP .
Decorator
Wrap, then still call
Logging, metrics, and retries sit in front of an object and still invoke it. Nobody in the line is allowed to skip the real work unless that is the decorator’s job.
Template
Outline always runs
Parse, validate, persist — every step. See Template Method. If you need to insert a step without a subclass, a list of handlers is more honest.
Java: auth, then balance, then the rest
Tests inject a shorter line. The ATM never names FraudHandler. Build the line once in a factory or the composition root — the same seam validation wants when rules grow.
interface Handler {
Handler setNext(Handler next);
void handle(Withdrawal w);
}
abstract class BaseHandler implements Handler {
private Handler next;
public Handler setNext(Handler next) {
this.next = next;
return next;
}
public void handle(Withdrawal w) {
if (next != null) next.handle(w);
}
}
class AuthHandler extends BaseHandler {
public void handle(Withdrawal w) {
if (!w.card().isValid()) throw new Unauthorized();
super.handle(w);
}
}
class BalanceHandler extends BaseHandler {
public void handle(Withdrawal w) {
if (w.account().balance().lessThan(w.amount())) throw new InsufficientFunds();
super.handle(w);
}
}
// Built once, outside the ATM:
// auth.setNext(balance).setNext(limit).setNext(fraud);ATM as the interview picture
Many ATM designs use both a State machine for “which buttons work now” and a chain for “this withdrawal is allowed.” Do not mash those into one switch.
What is the request object?
Withdrawal (or Payment) that already holds card, PIN, amount, and account. Handlers should not reach back into the ATM for data they forgot to put on the request.Who decides the order?
new AuthHandler(new BalanceHandler(...)) baked into AuthHandler couples the chapters.State for the session, chain for the checks
Smell
A chain that is still one method
Five private methods called in order from withdraw() is not the pattern. You cannot insert a handler without editing that method. The line must be objects you can relink.
Smell
Every handler names the next concrete class
Hold a Handler next, or build the line outside. Otherwise a new KYC check still edits AuthHandler.
Nearby in LLD
Behavioral family: who handles the request, not how the object is built.