Design a Vending Machine
In a 45-minute LLD interview, the interviewer assesses finite state modeling (eliminating boolean flags and monolithic switch-statements via the State pattern) and transactional integrity (ensuring inventory is never deducted prematurely, and exact refunds/change are calculated using integer currency). Scope the solution to three core lifecycle states (IdleState, HasMoneyState, DispensingState), product slot inventory management, coin/currency accumulation, dispensing with change return, and user-initiated cancellation. Mention cash cassette coin-change depletion (Greedy/DP change maker) and digital UPI/card payments as natural extensions.
Problem statement & clarifying requirements
Design an automated Vending Machine system. The machine must manage inventory across multiple product slots, accept cash/coin insertions, allow item selection, calculate and dispense correct change, and support transaction cancellation with full refunds. The lifecycle must be modeled cleanly using the State pattern so that operations invalid in a given state (such as dispensing without payment or cancelling during dispensing) are rejected without sprawling conditional checks.
Three primary lifecycle states: IdleState (waiting for customer), HasMoneyState (customer inserted currency, can select products or cancel), and DispensingState (verifying stock, deducting inventory, releasing product and change).
The machine remains in HasMoneyState, displays the shortfall amount, and preserves the inserted balance so the user can insert more money or press cancel.
The machine calculates change = balance - itemPrice, dispenses the item and change, resets the session balance to 0, and returns to IdleState.
Cancellation is allowed exclusively during HasMoneyState, triggering a full refund of all inserted coins. Cancellation is rejected during IdleState (nothing to refund) and DispensingState (physical delivery in progress).
First, sketch the design yourself
Spend 5 minutes listing the classes, who owns whom, and which interface hides the part that changes.
- 1.
Do not use an enum
VendingMachineStatepaired with massiveswitch (state_)blocks in every method. Use the State pattern to encapsulate each state's rules in dedicated polymorphic classes. - 2.
Ensure state transitions are explicit and driven by the active state:
IdleStatetransitions toHasMoneyStateon coin insertion;HasMoneyStatetransitions toDispensingStateon valid product selection or back toIdleStateon refund. - 3.
Decouple catalog and stock bookkeeping into a standalone
Inventoryclass to honor the Single Responsibility Principle (SRP).
How to think through this problem (5-step walkthrough)
In a 45-minute LLD interview, the interviewer assesses finite state modeling (eliminating boolean flags and monolithic switch-statements via the State pattern) and transactional integrity (ensuring inventory is never deducted prematurely, and exact refunds/change are calculated using integer currency). Scope the solution to three core lifecycle states (IdleState, HasMoneyState, DispensingState), product slot inventory management, coin/currency accumulation, dispensing with change return, and user-initiated cancellation. Mention cash cassette coin-change depletion (Greedy/DP change maker) and digital UPI/card payments as natural extensions.
Not every noun in the prompt deserves its own class. Separate dumb data structs from stateful managers, and turn trivial nouns into fields or enums.
Product / SlotProduct represents an immutable item (name, price in integer rupees/paise), while Slot pairs a Product with its remaining inventory count.
InventoryEncapsulates stock tracking across slot codes (std::unordered_map<std::string, Slot>), providing stock inspection and atomic deduction upon successful purchase.
VendingStatePolymorphic State interface declaring permitted operations: insertCoin, selectSlot, dispense, and refundCancel.
VendingMachineContext entity holding the current state (std::unique_ptr<VendingState>), Inventory, accumulated balance, and selected slot, exposing the client-facing API.
Button / DisplayScreenTrap noun — beginners often introduce separate Button, Keypad, or DisplayScreen classes. Physical buttons are mere hardware input signals that invoke API methods (selectSlot, refundCancel), and screen text is formatted return output or console logging, not persistent domain entities.
A naive implementation uses an enum State { IDLE, HAS_MONEY, DISPENSING } and writes a switch (state_) block in every method of VendingMachine. Adding a new operation (e.g. requestReceipt or applyPromoCode) forces editing every single switch block. Edge-case bugs proliferate: e.g. a user presses cancel while dispensing is physically in progress, or inserts coins after selecting a sold-out item, corrupting machine balance and inventory.
A centralized switch (state_) across all operations violates OCP and turns every new feature into a risk of invalid state combinations (e.g. dispensing without money or cancelling during dispensing).
Interleaving inventory decrement logic with coin validation leads to double-decrement or lost stock on transaction failure.
- ✓
Atomic payment-before-dispense invariant: Inventory is deducted and change is returned only after confirming
balance >= product.priceand successfully transitioning toDispensingState. - ✓
Refund conservation invariant: In
HasMoneyState, cancelling returns the exact accumulated balance to the user and resets the session balance to 0 before transitioning toIdleState. - ✓
Integer currency invariant: All prices, inserted coins, and change amounts are tracked as integers (rupees or paise) to eliminate floating-point rounding errors.
Entities & design patterns used
Unlock Full UML Diagram & C++23 Solution
The complete UML diagram, production-ready C++23 code, follow-up extensions, and design pitfall analysis are part of Brute2Best Pro. All 7 foundation chapters are 100% free.
First anchor question per pattern, Part 1 LLD & Module 1 C++ basics are 100% Free forever.