ReviseAlgo Logo

LLD Case Studies

Design Vending Machine

Design an automated vending machine system using the State Design Pattern to manage transactions, inventory, and payment changes.

Last Updated: June 26, 2026 23 min read

1. Requirements & Assumptions

Functional Requirements

  • The vending machine holds multiple product slots, each identified by a unique code (e.g., A1, B2).
  • Accepts coins (e.g., $0.10, $0.25, $1.00) and bills ($1.00, $5.00).
  • Supports state transitions: Idle, HasMoney, Dispensing, OutOfStock.
  • Validates inserted coins/bills, select products, and returns change.
  • Allows users to cancel the transaction at any time before dispensing to receive a full refund.

Non-Functional Requirements

  • Transactional Integrity: The machine must not dispense a product unless the payment is fully validated, and must return the correct change.
  • Modularity: Adding new states or product codes should be easy.

Assumptions

  • The machine runs as an embedded system with a single execution loop.
  • The coin inventory for returning change is finite.

2. Entities, Responsibilities & Relationships

  • VendingMachine (Context): Holds active states, balance, and inventory references. Delegates operations to the current state object.
  • State (Interface): Declares methods for insertion, selection, cancel, and dispense.
  • IdleState, HasMoneyState, DispensingState: Concrete states implementing state-specific behaviors.
  • Inventory: Tracks products and quantities available in each slot.
  • CoinBasket: Manages internal coin counts to calculate and dispense change.

3. Diagrams

UML Class Diagram

State Transition Diagram

4. Design Decisions

  • State Pattern: Eliminates complex conditional chains (if-else or switch blocks) by representing each machine state as a separate class.
  • Atomic Dispensing: Decrementing inventory and calculating change are executed inside a single state transition, ensuring data consistency.

5. Step-by-Step Implementation

  1. Define the Product entity with name and price fields.
  2. Implement Inventory to manage product mappings and stock quantities.
  3. Create the polymorphic State interface.
  4. Implement concrete states: IdleState, HasMoneyState, and DispensingState.
  5. Create the VendingMachine context class to manage active states, balance, and inventory.

6. Complete Code

7. Test Cases & Verification

  • Test Case 1: Insufficient Balance: Insert $1.00 for a $1.50 Soda. Verify that product selection is rejected and the balance remains at $1.00.
  • Test Case 2: Out of Stock Selection: Select a product slot with 0 quantity. Verify that the request is rejected and money is retained in the machine.
  • Test Case 3: Cancel Refund: Insert $2.00 and hit cancel. Verify that the machine returns $2.00 and transitions back to the Idle state.

8. Scalability & SOLID Improvements

  • SOLID - Single Responsibility Principle: The Inventory class handles product mapping and stock tracking, while states handle logical transition rules. This keeps the classes small and cohesive.
  • Extensibility: Adding a payment terminal (e.g. card/NFC payments) is simple. We can introduce a CardPaymentState that implements the State interface, extending the machine's capabilities without modifying existing state classes.

9. Production Considerations

  • Finite Coin Reserve: Exit logic should verify if the machine's internal coin cache has enough coins to return change. If not, the machine must display a warning (e.g. "Exact Change Only") and reject transactions that require change.
  • Hardware API Interfacing: In a physical machine, state changes are tied to hardware sensors (e.g., coin drop gates, laser sensors to verify product dispensing). We can use the Observer Pattern to listen to these sensor interrupts.

10. Next Lesson Preview

In the next case study, we will design a Rate Limiter. We will study the Token Bucket and Sliding Window algorithms, thread-safety, and concurrent request filtering!