Update / load inventory
Customer purchase item(s)
Accept payment (card, cash and coin)
Check low stock / functionality and call technician
from typing import Dict
class InventoryManager:
def __init__(self):
self.inventory_dict: Dict[str, 'Item'] = {}
def add_item(self, item_name: str, quantity: int, price: float) -> bool:
"""Add or update an item in the inventory."""
if item_name in self.inventory_dict:
self.inventory_dict[item_name].quantity += quantity
else:
self.inventory_dict[item_name] = Item(item_name, price, quantity)
return True
def get_items(self) -> Dict[str, 'Item']:
"""Return all items in the inventory."""
return self.inventory_dict
def get_item(self, item_name: str) -> int:
"""Get the quantity of a specific item."""
item = self.inventory_dict.get(item_name)
return item.quantity if item else 0
def update_item(self, item_name: str, quantity_delta: int) -> bool:
"""Update the quantity of an item."""
if item_name in self.inventory_dict:
new_quantity = self.inventory_dict[item_name].quantity + quantity_delta
if new_quantity < 0:
raise ValueError("Quantity cannot be negative.")
self.inventory_dict[item_name].quantity = new_quantity
return True
return False
class Payment:
def accept_payment(self, payment_method: str) -> bool:
if payment_method == "coin":
return CoinProcessor().accept_payment()
elif payment_method == "cash":
return CashProcessor().accept_payment()
elif payment_method == "card":
return CardProcessor().accept_payment()
else:
print("Unsupported payment method.")
return False
class CoinProcessor(Payment):
def accept_payment(self) -> bool:
print("Coin payment accepted.")
return True
class CashProcessor(Payment):
def accept_payment(self) -> bool:
print("Cash payment accepted.")
return True
class CardProcessor(Payment):
def accept_payment(self) -> bool:
print("Card payment accepted.")
return True
class Alerts:
def notify(self, status: str):
pass
class PaymentAlert(Alerts):
def notify(self, status: str):
if status == "payment failed":
print("Payment Alert: A payment failure has occurred.")
class RestockAlert(Alerts):
def notify(self, status: str):
if status == "item out of stock":
print("Restock Alert: Item out of stock, please refill.")
class MaintenanceAlert(Alerts):
def notify(self, status: str):
if status == "needs maintenance":
print("Maintenance Alert: The vending machine needs maintenance.")
Determine how these objects will interact with each other to fulfill the use cases...
Payment interfaced is implemented by all of cashProcessor,cardProcesoor and coinProcessor.
Observer pattern
Strategy pattern
from typing import List, Dict
from collections import deque
Item Class
class Item:
def init(self, name: str, price: float, quantity: int):
self.name = name
self.price = price
self.quantity = quantity
def decrease_quantity(self, amount: int):
if amount > self.quantity:
raise ValueError("Not enough items in stock.")
self.quantity -= amount
def __str__(self):
return f"Item(name={self.name}, price={self.price}, quantity={self.quantity})"
Inventory Manager Class
class InventoryManager:
def init(self):
self.inventory_dict: Dict[str, Item] = {}
def add_item(self, item_name: str, quantity: int, price: float) -> bool:
if item_name in self.inventory_dict:
self.inventory_dict[item_name].quantity += quantity
else:
self.inventory_dict[item_name] = Item(item_name, price, quantity)
return True
def get_items(self) -> Dict[str, Item]:
return self.inventory_dict
def get_item(self, item_name: str) -> int:
item = self.inventory_dict.get(item_name)
return item.quantity if item else 0
def update_item(self, item_name: str, quantity_delta: int) -> bool:
if item_name in self.inventory_dict:
new_quantity = self.inventory_dict[item_name].quantity + quantity_delta
if new_quantity < 0:
raise ValueError("Quantity cannot be negative.")
self.inventory_dict[item_name].quantity = new_quantity
return True
return False
def set_item_price(self, item_name: str, price: float) -> bool:
if item_name in self.inventory_dict:
self.inventory_dict[item_name].price = price
return True
return False
Abstract Payment Class
class Payment:
def accept_payment(self, payment_method: str) -> bool:
if payment_method == "coin":
return CoinProcessor().accept_payment()
elif payment_method == "cash":
return CashProcessor().accept_payment()
elif payment_method == "card":
return CardProcessor().accept_payment()
else:
print("Unsupported payment method.")
return False
Payment Processor Classes
class CoinProcessor(Payment):
def accept_payment(self) -> bool:
print("Coin payment accepted.")
return True
class CashProcessor(Payment):
def accept_payment(self) -> bool:
print("Cash payment accepted.")
return True
class CardProcessor(Payment):
def accept_payment(self) -> bool:
print("Card payment accepted.")
return True
Alerts Base Class and Specific Alerts
class Alerts:
def notify(self, status: str):
pass
class PaymentAlert(Alerts):
def notify(self, status: str):
if status == "payment failed":
print("Payment Alert: A payment failure has occurred.")
class RestockAlert(Alerts):
def notify(self, status: str):
if status == "item out of stock":
print("Restock Alert: Item out of stock, please refill.")
class MaintenanceAlert(Alerts):
def notify(self, status: str):
if status == "needs maintenance":
print("Maintenance Alert: The vending machine needs maintenance.")
Vending Machine Class
class VendingMachine:
def init(self, inventory_manager: InventoryManager, payment_processor: Payment):
self.inventory_manager = inventory_manager
self.payment_processor = payment_processor
self.status = "ready"
self.alerts: List[Alerts] = []
def add_alert(self, alert: Alerts):
self.alerts.append(alert)
def notify_alerts(self, status: str):
for alert in self.alerts:
alert.notify(status)
def lookup_items(self) -> Dict[str, Item]:
return self.inventory_manager.get_items()
def check_item_stock(self, item_name: str) -> int:
return self.inventory_manager.get_item(item_name)
def purchase_item(self, item_name: str, quantity: int) -> bool:
if self.check_item_stock(item_name) < quantity:
self.status = "item out of stock"
self.notify_alerts(self.status)
return False
if not self.process_payment():
self.status = "payment failed"
self.notify_alerts(self.status)
return False
self.inventory_manager.update_item(item_name, -quantity)
self.status = "dispensing"
print(f"Dispensing {quantity} of {item_name}.")
self.status = "ready"
return True
def process_payment(self) -> bool:
retries = 3
for _ in range(retries):
payment_method = input("Choose a payment method (coin, cash, card): ").strip().lower()
if payment_method in ["coin", "cash", "card"]:
if self.payment_processor.accept_payment(payment_method):
return True
else:
print("Payment failed. Please try again.")
self.status = "payment failed"
return False
Main Execution and Example Usage
if name == "main":
# Setup the vending machine
inventory_manager = InventoryManager()
payment_processor = Payment()
vending_machine = VendingMachine(inventory_manager, payment_processor)
# Add some items
inventory_manager.add_item("Soda", 10, 1.5)
inventory_manager.add_item("Chips", 5, 1.0)
inventory_manager.add_item("Candy", 20, 0.75)
# Register alert observers
payment_alert = PaymentAlert()
restock_alert = RestockAlert()
maintenance_alert = MaintenanceAlert()
vending_machine.add_alert(payment_alert)
vending_machine.add_alert(restock_alert)
vending_machine.add_alert(maintenance_alert)
# Simulate purchase
vending_machine.purchase_item("Chips", 2)
Single relationship principle:
Flexble to add new items, new paymenthods and new alerts
Try creating a class, flow, state and/or sequence diagram using the diagramming tool. Mermaid flow diagrams can be used to represent system use cases. You can ask the interviewer bot to create a starter diagram if unfamiliar with the tool. Briefly explain your diagrams if necessary...