Early Access: 87 spots left.

Claim
Low Level DesignInterview QuestionsDesign a Vending Machine

Course content

Design a Vending Machine

Medium·Tagsllddesignvending-machinestateencapsulation

Problem Statement

Design a vending machine that holds an inventory of items, accepts coins, and dispenses items with the correct change. Prices and balances are in cents (integers — no floating-point money). API contract ```java class VendingMachine { public VendingMachine(); // starts with no inventory and zero balance /** Stock an item code with a unit price (cents) and an initial quantity. Calling stock * on an existing code REPLACES the price and quantity for that code (lets the operator * restock). Throws IllegalArgumentException for non-positive priceCents or negative * quantity. */ public void stock(String code, int priceCents, int quantity); /* Add money to the inserted balance. Throws IllegalArgumentException for cents <= 0. / public void insertCoin(int cents); /** Dispense the requested item. * - Throws IllegalArgumentException if the code is unknown. * - Throws IllegalStateException if the item is out of stock. * - Throws IllegalStateException if the inserted balance is less than the price. - On success: decrement inventory, return change (balance - price), reset balance to 0. / public int dispense(String code); /** Return all inserted money to the customer and reset balance to 0. Returns the amount * refunded (0 if nothing was inserted). Always succeeds. */ public int refund(); public int getBalance(); public int getInventory(String code); // returns 0 for unknown codes } ``` The validator runs three checks: 1. *dispense_basic_and_change* — stock `"A1"` at 150¢ × 2; insert 200¢; `dispense("A1")` returns 50¢ change, decrements inventory to 1, resets balance to 0. Insert 150¢, dispense again → returns 0¢ change, inventory now 0. 2. *error_states* — `dispense("GHOST")` throws `IllegalArgumentException` (unknown code). `dispense` with insufficient inserted balance throws `IllegalStateException`; the inserted balance and inventory are unchanged. `dispense` of a sold-out item throws `IllegalStateException`. 3. *refund_resets_balance* — insert 100¢ + 50¢, `refund()` returns 150¢, `getBalance()` is 0, the machine can accept new coins and dispense again. The stub `VendingMachine` throws `UnsupportedOperationException` from every method, so it fails every check until you implement it. Starter code and validators are available in Java, Python, and C++.

Examples

Example 1
Input
var v = new VendingMachine(); v.stock("A1", 150, 2); v.insertCoin(200); v.dispense("A1")
Output
"50"
Why
200¢ inserted, 150¢ price → 50¢ change. Inventory drops to 1 and balance resets to 0.
Example 2
Input
v.insertCoin(50); v.dispense("A1")
Output
"throws IllegalStateException"
Why
50¢ < 150¢ price. The dispense fails; the 50¢ stays in the machine for a second insertCoin or a refund.
Example 3
Input
v.insertCoin(100); v.refund(); v.getBalance()
Output
"0"
Why
Refund returns the inserted 100¢ to the customer and resets the inserted balance.

Constraints

  • All amounts are in cents (int).
  • stock(code, priceCents, quantity) throws IllegalArgumentException if priceCents <= 0 or quantity < 0. Re-stocking an existing code replaces both price and quantity.
  • insertCoin(cents) throws IllegalArgumentException if cents <= 0.
  • dispense throws IllegalArgumentException for unknown codes; IllegalStateException for out-of-stock or insufficient balance.
  • On a successful dispense, balance resets to 0 (the change is returned, not retained).
  • On a failed dispense, balance and inventory are unchanged.
  • refund always succeeds and returns the inserted balance (0 if nothing was inserted).

Hints

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

Hint 1
Use a small inner class (or record) to bundle price and quantity per item: `class ItemRecord { int priceCents; int quantity; }` — held in a Map<String, ItemRecord>.
Hint 2
Use IllegalArgumentException for caller bugs (bad input, unknown code) and IllegalStateException for machine-state issues (out of stock, insufficient balance). The validator distinguishes these.
Hint 3
On a failed dispense, do NOT consume the balance or decrement inventory. The natural way is: validate everything first, then mutate. Failing midway through is the bug everyone makes once.
Hint 4
Successful dispense: return (balance - price) and reset balance to 0. The customer received their change; the machine has no money owed.
Hint 5
refund() is a guaranteed-success operation: read the balance, set balance = 0, return the saved value. It can be called when balance is already 0 (returns 0).