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.