Preview — Pro guide
You are seeing a portion of this guide. Sign in and upgrade to unlock the full article, quizzes, and interview answers.
LLD Case Study: Vending Machine
Design a production-grade vending machine with multi-payment support, change dispensing, and inventory management. Covers State, Strategy, and Observer patterns applied to a canonical LLD interview problem.
Clarifying Questions — What to Ask Before Designing
Payment methods supported?
Coins only? Bills? Credit/debit card? Contactless (NFC)? This is the most consequential question — each payment type needs its own validation logic, accumulation strategy, and refund path. Cards require network I/O and timeout handling that coins don't.
Is change-making required? What denominations?
The machine needs an internal denomination inventory. If it runs out of quarters, it may reject certain payment amounts even with sufficient total funds. Ask: what happens if the machine cannot make exact change — reject payment or go to EXACT_CHANGE_ONLY mode?
Product types and constraints?
Just snacks/beverages, or temperature-controlled items? Age-restricted items (alcohol, tobacco) requiring ID verification? This affects Slot design and the DISPENSING logic.
Network connectivity — standalone or fleet-managed?
Standalone: all state is local. Fleet-managed: remote inventory updates, remote pricing, transaction log sync. Changes Observer topology and whether inventory alerts are local buzzer vs. remote API call.
Refund and cancellation policy?
Can the user cancel mid-payment and get coins back? What happens if dispensing fails — product stuck? Is there a manual override/maintenance mode? This adds the REFUND_IN_PROGRESS and MAINTENANCE states.
Entity Extraction — From Requirements to Classes
The most common mistake in vending machine design is treating inventory as product-based ('how many Cokes are there?') instead of slot-based ('how many items are in slot A3?'). In a real machine, each physical slot has a fixed capacity and a currently-loaded product. The same product can occupy multiple slots. This matters for restocking: a technician fills physical slots, not abstract product buckets.
Core entities:
VendingMachine— the central Singleton that coordinates state and delegates to subsystemsSlot— physical slot withslot_id,product,quantity,capacity; the unit of inventoryProduct—product_id,name,price,category(for age restriction checks); immutable value objectInventory— manages the slot grid, exposesget_slot(),dispense_from_slot(),restock(), fires low-inventory eventsPayment(abstract) — subclasses:CoinPayment,BillPayment,CardPayment; each knows how to validate and accumulateTransactionProcessor— owns the current transaction: amount inserted, product selected, change owedChangeDispenser— tracks denomination counts, runs the greedy change algorithm, knows when it's unable to make changeDisplay— Observer of VendingMachine state, renders messages per state
Key relationship: VendingMachine has-a Inventory, has-a ChangeDispenser, has-a TransactionProcessor, and is a state machine — its current state determines which operations are legal.