Chain of Responsibility: Expense Approval
Problem
Expense requests pass through a chain of approvers. A clerk approves amounts up to 100, a manager up to 1000 and a director up to 10000. If an approver cannot handle the amount, the request goes to the next one in the chain; after the director, the request is rejected. Amounts of 0 or less are invalid. For each amount print approved by clerk, approved by manager, approved by director, rejected or invalid. Build the chain from linked handler objects, with no if-else ladder in the main loop.
Constraints
- 1 <= lines <= 10^4
- |amount| <= 10^9
Examples
Input
50 101 20000
Output
approved by clerk approved by manager rejected
Solutions
The sender only knows the first handler. New approvers can be added or reordered by changing how the chain is built, without touching the handlers or the caller. Web frameworks use the same idea for middleware and servlet filters.
/*
* Problem : Process lines.
* Input : Several lines.
* Output : One decision per request.
* Approach: Linked handlers.
* Time : O(n)
* Space : O(1)
* Java : 8 or newer.
*/
import java.util.Scanner;
public class Main {
// Step 1: Every handler has a limit and a link to the next handler. Without a next handler the request is rejected.
static class Approver {
private final String title;
private final long limit;
private final Approver next;
Approver(String title, long limit, Approver next) {
this.title = title;
this.limit = limit;
this.next = next;
}
// Step 2: Handle the request here if the amount fits. Otherwise pass it to the next link of the chain.
String handle(long amount) {
if (amount <= limit) {
return "approved by " + title;
}
return next == null ? "rejected" : next.handle(amount);
}
}
// This method solves the task. It receives the input and returns the answer.
static String[] solve(String[] lines) {
// Step 3: Build the chain from the end: director first, then manager, then clerk.
Approver chain = new Approver("clerk", 100, new Approver("manager", 1000, new Approver("director", 10000, null)));
String[] output = new String[lines.length];
for (int i = 0; i < lines.length; i++) {
long amount = Long.parseLong(lines[i]);
output[i] = amount <= 0 ? "invalid" : chain.handle(amount);
}
return output;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
java.util.List<String> all = new java.util.ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (!line.isEmpty()) {
all.add(line);
}
}
String[] lines = all.toArray(new String[0]);
System.out.println(String.join("\n", solve(lines)));
}
}
Hints (1)
- What happens when a new approver level is needed?