0
0
LldHow-ToBeginner ยท 4 min read

How to Design a Vending Machine: System Design Guide

To design a vending machine, create components like Inventory, Payment, and Dispense modules that interact through clear interfaces. Use a State Machine pattern to manage states like idle, selection, payment, and dispensing for smooth operation.
๐Ÿ“

Syntax

The vending machine design involves defining key components and their interactions:

  • Inventory Module: Tracks available items and quantities.
  • Payment Module: Handles money input and validation.
  • Selection Module: Lets users choose items.
  • Dispense Module: Releases the selected item.
  • State Machine: Controls machine states like idle, waiting for payment, dispensing, and out of service.

Each module should have clear methods to perform its tasks and communicate with others.

python
class VendingMachine:
    def __init__(self):
        self.inventory = Inventory()
        self.payment = Payment()
        self.state = 'IDLE'

    def select_item(self, item_code):
        if self.state == 'IDLE' and self.inventory.is_available(item_code):
            self.state = 'WAITING_FOR_PAYMENT'
            return True
        return False

    def insert_money(self, amount):
        if self.state == 'WAITING_FOR_PAYMENT':
            self.payment.add(amount)
            if self.payment.is_sufficient():
                self.state = 'DISPENSING'
                self.dispense_item()

    def dispense_item(self):
        # Dispense logic here
        self.state = 'IDLE'

class Inventory:
    def is_available(self, item_code):
        # Check stock
        return True

class Payment:
    def add(self, amount):
        pass
    def is_sufficient(self):
        return True
๐Ÿ’ป

Example

This example shows a simple vending machine flow where a user selects an item, inserts money, and receives the item.

python
class Inventory:
    def __init__(self):
        self.stock = {'A1': 5, 'B2': 3}

    def is_available(self, item_code):
        return self.stock.get(item_code, 0) > 0

    def reduce_stock(self, item_code):
        if self.is_available(item_code):
            self.stock[item_code] -= 1

class Payment:
    def __init__(self, price):
        self.price = price
        self.amount_inserted = 0

    def add(self, amount):
        self.amount_inserted += amount

    def is_sufficient(self):
        return self.amount_inserted >= self.price

class VendingMachine:
    def __init__(self):
        self.inventory = Inventory()
        self.state = 'IDLE'
        self.selected_item = None
        self.payment = None

    def select_item(self, item_code):
        if self.state == 'IDLE' and self.inventory.is_available(item_code):
            self.selected_item = item_code
            self.payment = Payment(price=2)  # Assume fixed price
            self.state = 'WAITING_FOR_PAYMENT'
            return 'Item selected, please insert $2'
        return 'Item not available or machine busy'

    def insert_money(self, amount):
        if self.state == 'WAITING_FOR_PAYMENT':
            self.payment.add(amount)
            if self.payment.is_sufficient():
                self.state = 'DISPENSING'
                return self.dispense_item()
            else:
                return f'Inserted ${self.payment.amount_inserted}, please insert more'
        return 'No item selected or already dispensing'

    def dispense_item(self):
        self.inventory.reduce_stock(self.selected_item)
        self.state = 'IDLE'
        return f'Dispensing item {self.selected_item}'

# Usage
vm = VendingMachine()
print(vm.select_item('A1'))
print(vm.insert_money(1))
print(vm.insert_money(1))
Output
Item selected, please insert $2 Inserted $1, please insert more Dispensing item A1
โš ๏ธ

Common Pitfalls

Common mistakes when designing vending machines include:

  • Not handling state transitions properly, causing the machine to accept money without selection or dispense without payment.
  • Ignoring concurrency issues if multiple users interact simultaneously.
  • Failing to update inventory after dispensing, leading to incorrect stock levels.
  • Not validating payment amounts or giving change.

Always ensure clear state management and robust error handling.

python
class VendingMachineWrong:
    def __init__(self):
        self.state = 'IDLE'

    def insert_money(self, amount):
        # Wrong: accepts money even if no item selected
        print('Money accepted')

    def select_item(self, item_code):
        # Wrong: no state change
        print('Item selected')

# Correct approach uses state checks before actions as shown in previous example.
Output
Money accepted Item selected
๐Ÿ“Š

Quick Reference

Key tips for vending machine design:

  • Use a state machine to manage states: idle, selection, payment, dispensing.
  • Separate concerns: inventory, payment, selection, and dispensing modules.
  • Validate inputs and handle errors gracefully.
  • Keep inventory updated after each dispense.
  • Consider concurrency and thread safety if needed.
โœ…

Key Takeaways

Use a state machine to clearly manage vending machine states and transitions.
Separate inventory, payment, selection, and dispensing into distinct modules.
Always validate user inputs and payment before dispensing items.
Update inventory immediately after dispensing to maintain accuracy.
Handle errors and edge cases to ensure smooth user experience.