Skip to content
Low Level Design Mastery Logo
LowLevelDesign Mastery

Design a Vending Machine

Design a vending machine system that can sell multiple products, accept various payment methods, dispense products and change, and handle inventory management.

Design a vending machine system that can sell multiple products, accept various payment methods (coins and notes), dispense products and change, handle inventory management, and support concurrent users while maintaining thread safety.

In this problem, you’ll design a system that handles multi-step transactions, validates payments, and manages a physical inventory while ensuring that every coin and snack is accounted for.


Design a vending machine that supports multiple products, various payment denominations, and a robust transaction flow with clear error handling.

Functional Requirements:

  • Product Inventory: Sell multiple products, each with a price and quantity.
  • Multi-Payment: Accept various coins and notes (bills).
  • Transaction Logic: Provide the product and correct change after successful payment.
  • Inventory Tracking: Maintain real-time records of available stock for all products.
  • Payment Validation: Ensure sufficient funds are inserted before dispensing.
  • Full Flow: Manage selection → payment → validation → dispensing → change return.
  • Operator Actions: Support restocking and collecting stored money.
  • Error States: Handle insufficient funds, out-of-stock items, or inability to provide exact change.

Non-Functional Requirements:

  • Object-Oriented Design: Clearly separated roles for Machine, Inventory, and PaymentHandler.
  • Thread Safety: Protect inventory and balances from race conditions under concurrent access.
  • Modularity: Easy to add new payment methods or promotional pricing.
  • Maintainability: Use the State Pattern to avoid complex if-else chains and ensure valid transitions.
  • Reliability: The core logic must be easy to test and handle edge cases gracefully.

The system coordinates between the VendingMachine controller, InventoryManager, and PaymentHandler.

Diagram
classDiagram
    class VendingMachine {
        -State currentState
        -Inventory inventory
        -double currentBalance
        +insertMoney(amount)
        +selectProduct(code)
        +dispense()
    }
    
    class State {
        <<interface>>
        +insertMoney()
        +selectProduct()
        +dispense()
    }
    
    class Product {
        -String code
        -double price
        -int quantity
    }

    class Inventory {
        -Map~String, Product~ products
        +hasProduct(code)
        +updateQuantity(code, delta)
    }

    VendingMachine --> State
    VendingMachine --> Inventory
    Inventory o-- Product

Diagram

A vending machine should not allow a product selection if money hasn’t been inserted, and it shouldn’t allow money insertion while it’s in the middle of dispensing.

Solution: Use the State Pattern. Define classes like IdleState, HasMoneyState, DispensingState, and OutOfOrderState. The VendingMachine delegates its actions to the current state object, ensuring that only valid actions are performed at any given time.

If two people (or a user and a refill operator) interact with the machine simultaneously, you could end up with “phantom” stock or incorrect balances.

Solution: Use Atomic Operations or Synchronized Blocks. Wrap the check-and-decrement logic in a lock to ensure that if the system sees 1 item left, only one person can successfully buy it.

What if a user pays with a $10 bill for a $1.50 item, but the machine is out of quarters and dimes?

Solution: Implement Pre-Transaction Validation. Before accepting the money or starting the dispense process, the PaymentHandler should verify if it has enough denominations in its “coin bank” to provide the required change. If not, the transaction should be cancelled immediately.


By solving this problem, you’ll master:

  • State Pattern - Handling complex, state-dependent logic.
  • Concurrency - Protecting shared resources in real-time.
  • Financial Validation - Building robust transaction and change logic.
  • Hardware Abstraction - Designing software that maps to physical components.

Ready to see the full implementation? Open the interactive playground to access:

  • 🎯 Step-by-step guidance through the 8-step LLD approach
  • 📊 Interactive UML builder to visualize your design
  • 💻 Complete Code Solutions in Python, Java, C++, TypeScript, JavaScript, C#
  • 🤖 AI-powered review of your design and code

After mastering the Vending Machine, try these similar problems: