Software Development Engineer

Blog PostsResume

Low Level Design - Design a Vending Machine

Requirements

  1. The vending machine is divided into shelves with each shelf contains a specific product type.
  2. User selects a product by entering the shelf code.
  3. User selects the payment option.
  4. On successful payment, the product is dispensed.
  5. (Optional) Vending Machine sends notification to admin on Out of stock.

Class Diagram

enum ProductType
CHIPS, NACHOS, COOKIES, CRACKERS

enum UserType
CUSTOMER, ADMIN

enum PaymentType
CARD, UPI, CASH

class Product
-------------
- id: String
- name: String
- price: Double
- productType: ProductType

class ProductShelf
------------------
- shelfCode: Integer
- product: Product
- productCount: Integer
------------------------
+ getProduct(): Product
+ addProduct(): void
+ reduceCount(): void

class VendingMachine
--------------------
- id: String
- productShelves: ProductShelf[]
--------------------------------
+ selectProduct(): void
+ makePayment(): void

Design Choices

Incorporating Object-Oriented Design Patterns into the Vending Machine Low-Level Design can significantly enhance the system's modularity, maintainability, and scalability.

1. State Pattern

Managing the state of the vending machine, which can change based on the Order Status like product selection, payment, or product dispensing state.

interface VendingMachineState {
    void selectProduct(int shelfCode);
    void cancelPayment(String transactionId);
    void makePayment(String transactionId, PaymentType paymentType);
    void dispenseProduct(String transactionId);
} 

class ProductSelectionState implements VendingMachineState {
	private VendingMachine vendingMachine;

    @Override
	public void selectProduct(final int shelfCode) {
		// operation

		vendingMachine.setCurrentState(new PaymentState(vendingMachine));
	}
}

class PaymentState implements VendingMachineState {
	private VendingMachine vendingMachine;

    @Override
	public void makePayment(final String transactionId, final PaymentType paymentType) {
		// operation

		vendingMachine.setCurrentState(new DispensingState(vendingMachine));
	}

    @Override
	public void cancelPayment(final String transactionId) {
		// operation

		vendingMachine.setCurrentState(new ProductSelectionState(vendingMachine));
	}
}

class DispensingState implements VendingMachineState {
	private VendingMachine vendingMachine;

    @Override
	public void dispenseProduct(final String transactionId) {
		// operation

		vendingMachine.setCurrentState(new ProductSelectionState(vendingMachine));
	}
}

2. Strategy Pattern

To encapsulate algorithms or processes that can vary independently, like different payment processing methods or product selection strategies.

public interface PaymentStrategy {
    boolean processPayment(double amount);
}

public class CardPayment implements PaymentStrategy {
    @Override
    public boolean processPayment(double amount) {
        // Card payment logic
        return true;
    }
}

public class DigitalPayment implements PaymentStrategy {
    @Override
    public boolean processPayment(double amount) {
        // Digital payment logic
        return true;
    }
}

```java
public class VendingMachine {

    public static void main(String[] args) {
        PaymentStrategy paymentStragey = new DigitalPayment();
        paymentStrategy.processPayment(150);
    }
}

3. Adapter Pattern

Integrating with external systems or APIs, like payment gateways or inventory management systems, which may have different interfaces.

// Interface used by the vending machine to interact with all types of payment gateways.
public interface PaymentGateway {
    boolean processPayment(double amount);
}

class DigitalPaymentClient {
    public boolean makePayment(double amount) {
        // Digital payment logic
        return true;
    }
}

class CardPaymentClient {
    public boolean executeTransaction(double amount) {
        // Card payment logic
        return true;
    }
}

// Adapter for Digital Payment
class DigitalPaymentAdapter implements PaymentGateway {
    private DigitalPaymentClient digitalPaymentClient;

    @Override
    public boolean processPayment(double amount) {
        return digitalPaymentClient.makePayment(amount);
    }
}

// Adapter for Card Payment
class CardPaymentAdapter implements PaymentGateway {
    private CardPaymentClient cardPaymentClient;

    @Override
    public boolean processPayment(double amount) {
        return cardPaymentClient.executeTransaction(amount);
    }
}

4. (Optional) Observer Pattern

For notifying changes in the machine state or stock levels to various components such as the monitoring system or user interface.

public interface VendingMachineObserver {
    void update(String product, int quantity);
}

// Subject
public class VendingMachine {
    private Map<String, Integer> stock;
    private List<VendingMachineObserver> observers;

    public void dispenseProduct(String product) {
        int currentStock = stock.getOrDefault(product, 0);
        if (currentStock > 0) {
            stock.put(product, currentStock - 1);
        } else {
			notifyObservers();
        }
    }

    @Override
    public void registerObserver(VendingMachineObserver observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(VendingMachineObserver observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (VendingMachineObserver observer : observers) {
            for (Map.Entry<String, Integer> entry : stock.entrySet()) {
                observer.update(entry.getKey(), entry.getValue());
            }
        }
    }
}

public class Admin extends User implements VendingMachineObserver {
    @Override
    public void update(String product, int quantity) {
        if (quantity == 0) {
            System.out.println("Monitoring Alert: " + product + " is out of stock!");
        }
    }
}

API Specifications

Select Product

  • API: POST /vending/product
  • Request Body
    • shelfCode: Integer

Make Payment

  • API: POST /vending/payment
  • Request Body:
    • amount: double
    • paymentMethod: String

© 2024 Ujjwal Bhardwaj. All Rights Reserved.