Early Access: 87 spots left.

Claim
Low Level DesignChain of ResponsibilityChain of Responsibility: Build a Purchase Approval Chain

Course content

Chain of Responsibility: Build a Purchase Approval Chain

Medium·Tagsdesign-patternschain-of-responsibilitybehaviouralrefactoring

Problem Statement

An approval system needs to route purchase requests through three roles, each authorised up to a different spending limit: - Manager — handles requests up to $1,000 - Director — handles requests up to $10,000 - VP — handles requests up to $100,000 The chain forwards a request from the lowest authority upward until one approver can sign off. If the amount exceeds even the VP's limit, the chain returns `"REJECTED"`. The starter gives you the abstract `Approver` base class (with `next`, `setNext`, and a `forwardOrReject` helper) plus a `PurchaseRequest` value object. Implement the three concrete approvers: ```java class Manager extends Approver { public String approve(PurchaseRequest r); // amount <= 1_000 → return "Manager" // otherwise → forwardOrReject(r) } class Director extends Approver { public String approve(PurchaseRequest r); // amount <= 10_000 → return "Director" // otherwise → forwardOrReject(r) } class Vp extends Approver { public String approve(PurchaseRequest r); // amount <= 100_000 → return "VP" // otherwise → forwardOrReject(r) } ``` Wiring is fluent: `new Manager().setNext(new Director()).setNext(new Vp());` builds the chain in one expression because `setNext` returns the approver it received as an argument. The validator runs three checks: 1. each_role_handles_within_limit — a standalone `Manager` (no chain) returns `"Manager"` for $500 and `"REJECTED"` for $5,000 (no one to forward to). Same shape for `Director` (handles $5,000, rejects $50,000 standalone) and `Vp` (handles $50,000). 2. chain_forwards_to_next_handler — full chain Manager → Director → VP routes $500 to Manager, $5,000 to Director, $50,000 to VP. Each approver hands off without short-circuiting incorrectly. 3. chain_exhaustion_and_setnext — a $500,000 request through the full chain returns `"REJECTED"`; `setNext(x)` returns `x` (so chained `setNext` calls compile and work). The stub approvers throw `UnsupportedOperationException` from every method, so they fail every check until `approve` is implemented on each.

Examples

Example 1
Input
var chain = new Manager(); chain.setNext(new Director()).setNext(new Vp()); chain.approve(new PurchaseRequest(500, "laptop"))
Output
"\"Manager\""
Why
$500 is within Manager's limit; the chain stops at the first capable approver.
Example 2
Input
chain.approve(new PurchaseRequest(50_000, "servers"))
Output
"\"VP\""
Why
$50,000 exceeds Manager's $1k and Director's $10k. Both forward; VP handles.
Example 3
Input
chain.approve(new PurchaseRequest(500_000, "office expansion"))
Output
"\"REJECTED\""
Why
Even VP cannot authorise $500,000. The chain is exhausted and forwardOrReject returns 'REJECTED'.

Constraints

  • Manager, Director, and Vp must each extend Approver.
  • approve(PurchaseRequest) returns 'Manager', 'Director', or 'VP' when within that role's limit, otherwise forwards via forwardOrReject.
  • Manager limit: $1,000. Director limit: $10,000. VP limit: $100,000.
  • Use the inherited forwardOrReject(...) helper rather than calling next.approve(...) directly. The helper handles the null-next case for you.
  • approve must not throw for amounts that exceed every approver's limit — it returns 'REJECTED' instead.

Hints

Stuck? Reveal a nudge toward the right pattern, one step at a time.

Hint 1
Each approve() method is one ternary expression: amount <= LIMIT ? "<role>" : forwardOrReject(request).
Hint 2
Use the inherited forwardOrReject(...) helper rather than referencing `next` directly. The helper handles the null-next case (returns 'REJECTED') so you do not have to.
Hint 3
Manager limit is $1,000. Director is $10,000. VP is $100,000. The order in which the chain is wired determines who tries first; each role's limit is the only thing that determines who succeeds.
Hint 4
The role names returned must be exactly 'Manager', 'Director', 'VP' — capitalisation matters for the validator.