Card 04/ 08
Chain of Responsibility Example: Approving an Expense by Amount
A team lead approves up to 500, a manager up to 5,000, and a director anything above.
An approval process with spending limits is a natural Chain of Responsibility, and this example maps the template onto it. A team lead may approve an expense up to 500, a manager up to 5,000, and a director any amount. An employee submits every expense to their team lead, and it climbs only as far as it needs to.
| Template | Expense example |
|---|---|
| Handler | Approver, with a title, a limit and the next approver |
| ConcreteHandler | Three Approver objects with different limits |
| The handling test | amount <= self.limit |
| Client | The loop that sends each amount to team_lead |
class Approver:
def __init__(self, title: str, limit: float, next_approver: "Approver | None" = None) -> None:
self.title = title
self.limit = limit
self.next_approver = next_approver
def approve(self, amount: float) -> str:
if amount <= self.limit:
return f"{amount:,.0f} approved by the {self.title}"
if self.next_approver is None:
return f"{amount:,.0f} refused: above every limit"
print(f" {self.title} passes {amount:,.0f} up")
return self.next_approver.approve(amount)
director = Approver("director", float("inf"))
manager = Approver("manager", 5_000, director)
team_lead = Approver("team lead", 500, manager)
for amount in (120, 3_200, 48_000):
print(team_lead.approve(amount))120 approved by the team lead
team lead passes 3,200 up
3,200 approved by the manager
team lead passes 48,000 up
manager passes 48,000 up
48,000 approved by the directorThe 120 expense stops at the team lead, 3,200 climbs one level, and 48,000 climbs two, with each pass printed. The director's limit is infinity, so the chain always ends in a handler that accepts the request. The next_approver is None branch still refuses explicitly, in case a chain is built without a director.
The handlers here are one class with different data, not three classes. That is common when the handlers differ only in a value. When they differ in how they decide, such as one checking an amount and another checking a category, each becomes its own class.
← → move through sections and cards