“Revolutionizing Vending Machines: A Deep Dive into Java-Based Stateful Design for Intelligent Inventory Management”

Explore the design nuances of a Java-based Vending Machine system, featuring classes like Coin for currency representation, Product for item details, Rack for product storage, and VendingMachine orchestrating states, user balances, and inventory updates. Dive into stateful behaviors with classes like NoMoneyInsertedState and MoneyInsertedState offering a dynamic user experience. Witness seamless transitions between states and inventory management, showcasing the power of object-oriented design in vending machine systems.

  1. NoMoneyInsertedState:
    • Description: In this state, the vending machine is waiting for the user to insert money.
    • Behavior: Accepts coin insertions and transitions to the MoneyInsertedState.
  2. MoneyInsertedState:
    • Description: The vending machine is in this state when the user has inserted money but hasn’t selected a product yet.
    • Behavior: Continues to accept coin insertions and allows the user to select a product. After product selection, it transitions to the DispenseItemState.
import java.util.ArrayList;
import java.util.List;

enum Coin {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);

    private final int value;

    Coin(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

class Product {
    private final String name;
    private final double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }
}

class Rack {
    private final int rackNumber;
    private final List<Product> products;

    public Rack(int rackNumber) {
        this.rackNumber = rackNumber;
        this.products = new ArrayList<>();
    }

    public void addProduct(Product product) {
        products.add(product);
    }

    public List<Product> getProducts() {
        return products;
    }

    public void removeProduct(Product product) {
        products.remove(product);
    }
}

interface VendingMachineStateContext {
    void insertCoin(Coin coin);

    void selectProduct(int rackNumber, int productIndex);
}

class NoMoneyInsertedState implements VendingMachineStateContext {
    private final VendingMachine vendingMachine;

    public NoMoneyInsertedState(VendingMachine vendingMachine) {
        this.vendingMachine = vendingMachine;
    }

    @Override
    public void insertCoin(Coin coin) {
        vendingMachine.insertCoin(coin);
        vendingMachine.changeState(VendingMachineState.MONEY_INSERTED);
    }

    @Override
    public void selectProduct(int rackNumber, int productIndex) {
        System.out.println("Please insert money first.");
    }
}

class MoneyInsertedState implements VendingMachineStateContext {
    private final VendingMachine vendingMachine;

    public MoneyInsertedState(VendingMachine vendingMachine) {
        this.vendingMachine = vendingMachine;
    }

    @Override
    public void insertCoin(Coin coin) {
        vendingMachine.setUserBalance(vendingMachine.getUserBalance() + coin.getValue() / 100.0);
    }

   @Override
    public void selectProduct(int rackNumber, int productIndex) {
        Rack selectedRack = vendingMachine.getRacks().get(rackNumber - 1);
        List<Product> products = selectedRack.getProducts();

        if (productIndex < 1 || productIndex > products.size()) {
            System.out.println("Invalid product index");
            return;
        }

        Product selectedProduct = products.get(productIndex - 1);

        if (vendingMachine.getUserBalance() >= selectedProduct.getPrice()) {
            // Sufficient funds, process the purchase
            System.out.println("Dispensing: " + selectedProduct.getName());
            vendingMachine.updateInventory(selectedRack, selectedProduct);
            vendingMachine.setUserBalance(vendingMachine.getUserBalance() - selectedProduct.getPrice());
            vendingMachine.changeState(VendingMachineState.NO_MONEY_INSERTED);
        } else {
            System.out.println("Insufficient funds");
        }
    }
}


enum VendingMachineState {
    NO_MONEY_INSERTED, MONEY_INSERTED, DISPENSE_ITEM
}

class VendingMachine {
    private final List<Rack> racks;
    private double userBalance;
    private VendingMachineStateContext currentState;

    public VendingMachine() {
        this.racks = new ArrayList<>();
        this.userBalance = 0.0;
        this.currentState = new NoMoneyInsertedState(this);
    }

    public void addRack(Rack rack) {
        racks.add(rack);
    }

    public List<Rack> getRacks() {
        return racks;
    }

    public double getUserBalance() {
        return userBalance;
    }

    public void insertCoin(Coin coin) {
        currentState.insertCoin(coin);
    }

    public void selectProduct(int rackNumber, int productIndex) {
        currentState.selectProduct(rackNumber, productIndex);
    }

    public void changeState(VendingMachineState newState) {
        switch (newState) {
            case NO_MONEY_INSERTED:
                currentState = new NoMoneyInsertedState(this);
                break;
            case MONEY_INSERTED:
                currentState = new MoneyInsertedState(this);
                break;
            case DISPENSE_ITEM:
                currentState = new DispenseItemState();
                break;
        }
    }

    public void updateInventory(Rack rack, Product product) {
        rack.removeProduct(product);
    }

    public static void main(String[] args) {
        VendingMachine vendingMachine = new VendingMachine();

        Rack rack1 = new Rack(1);
        rack1.addProduct(new Product("Soda", 1.50));
        rack1.addProduct(new Product("Chips", 1.25));
        vendingMachine.addRack(rack1);

        Rack rack2 = new Rack(2);
        rack2.addProduct(new Product("Water", 1.00));
        rack2.addProduct(new Product("Chocolate", 1.75));
        vendingMachine.addRack(rack2);

        vendingMachine.insertCoin(Coin.QUARTER);
        vendingMachine.insertCoin(Coin.DIME);
        vendingMachine.selectProduct(1, 1);

        vendingMachine.insertCoin(Coin.NICKEL);
        vendingMachine.insertCoin(Coin.PENNY);
        vendingMachine.selectProduct(2, 2);

        Product newProduct = new Product("Juice", 2.00);
        rack1.addProduct(newProduct);

        vendingMachine.selectProduct(1, 3);
    }
}

You may also like...