Showing posts with label Vending Machine. Show all posts
Showing posts with label Vending Machine. Show all posts

Saturday, 1 February 2014

State Design pattern - Implementation [Vending Machine]

Master Practical Java Architecture & Design Patterns!

Subscribe to Ram N Java for clean coding tutorials, GoF design patterns, and real-world system implementations!

🔔 Subscribe to Ram N Java

The Vending Machine Challenge

A classic interview and system design challenge is the Vending Machine. A vending machine moves through multiple states:

  • No Coin Inserted: Waiting for payment before accepting a product selection.
  • Coin Inserted: Validates credit, allows selection, or refunds the coin upon cancellation.
  • Dispensing Item: Releases the chosen product and checks if stock remains.
  • Sold Out: Disables purchases when the inventory is empty.

Writing this with nested if-else or switch-case statements turns every user action (insert coin, select item, press cancel) into complex branching logic where state transitions are brittle and error-prone.

Architecture of the State Pattern Solution

The State Design Pattern encapsulates state-specific behaviors into individual classes, letting the vending machine change its behavior dynamically:

  • State Interface: Outlines the key vending actions: insertCoin(), pressButton(), and dispense().
  • Concrete State Classes: Classes such as NoCoinState, HasCoinState, DispensingState, and SoldOutState implement the actions valid for that state and transition the machine context to the next state.
  • Context Class (VendingMachine): Holds the inventory, maintains a reference to the active state, and simply delegates incoming user requests to the current state object.

Key Architectural Benefits

Implementing the vending machine with the State pattern delivers immediate engineering advantages:

  • Elimination of Massive Conditionals: Replaces deep conditional trees with clean, polymorphic method calls.
  • Single Responsibility Principle: Each state’s transition rules and actions are isolated in their own class.
  • Open/Closed Principle: Adding new states (e.g., maintenance mode, contactless pay) does not alter existing operational state classes.

Related Tutorials from Ram N Java


Click here to watch in Youtube : https://www.youtube.com/watch?v=VIzWKPRG9lo

Click the below Image to Enlarge
State Design pattern - Implementation [Vending Machine]
State Design pattern - Implementation [Vending Machine] - Class Diagram










































VendingMachineState.java


public interface VendingMachineState
{

public void selectProductAndInsertMoney(int amount,String productName);

public void dispenseProduct();

}

HasMoneyState.java

public class HasMoneyState implements VendingMachineState
{

@Override
public void selectProductAndInsertMoney( int amount, String productName )
{
System.out.println("Already Vending machine has money and product selected,So wait till it finish the current dispensing process ... ");

}

@Override
public void dispenseProduct()
{
System.out.println("Vending Machine  dispensed the product ...");

}

}

NoMoneyState.java

public class NoMoneyState implements VendingMachineState
{

@Override
public void selectProductAndInsertMoney( int amount, String productName )
{
System.out.println(amount + "Rs has been inserted and " + productName + " has been selected...");

}

@Override
public void dispenseProduct()
{
System.out.println("Vending Machine cannot dispense product because money is not inserted and product is not selected...");

}

}

VendingMachine.java

// This is like Context
public class VendingMachine implements VendingMachineState
{

private VendingMachineState vendingMachineState;

public VendingMachine()
{
vendingMachineState = new NoMoneyState();
}

public VendingMachineState getVendingMachineState()
{
return vendingMachineState;
}

public void setVendingMachineState( VendingMachineState vendingMachineState )
{
this.vendingMachineState = vendingMachineState;
}

@Override
public void selectProductAndInsertMoney( int amount, String productName )
{
vendingMachineState.selectProductAndInsertMoney(amount, productName);
VendingMachineState hasMoneyState = new HasMoneyState();
/*
* Money has been inserted so vending Machine changed the
* internal state to 'hasMoneyState'
*/

if( vendingMachineState instanceof NoMoneyState )
{
setVendingMachineState(hasMoneyState);
System.out.println("VendingMachine internal state has been moved to : "
               + vendingMachineState.getClass().getName());
}

}

@Override
public void dispenseProduct()
{
VendingMachineState noMoenyState = new NoMoneyState();
vendingMachineState.dispenseProduct();

/*
* Product has been dispensed so vending Machine changed the
* internal state to 'NoMoneyState'
*/
if( vendingMachineState instanceof HasMoneyState )
{
setVendingMachineState(noMoenyState);
System.out.println("VendingMachine internal state has been moved to : "
               + vendingMachineState.getClass().getName());
}

}

}

Client.java

public class Client
{

public static void main( String[] args )
{

/*
* Initially Vending Machine will be 'noMoneyState'
*/
VendingMachine vendingMachine = new VendingMachine();

System.out.println("Current VendingMachine State : "
               + vendingMachine.getVendingMachineState().getClass().getName()+"\n");

vendingMachine.dispenseProduct();
vendingMachine.selectProductAndInsertMoney(100, "Pepsi");

/*
* Money has been inserted so vending Machine changed the
* internal state to 'hasMoneyState'
*/

System.out.println("\nCurrent VendingMachine State : "
               + vendingMachine.getVendingMachineState().getClass().getName()+"\n");

vendingMachine.selectProductAndInsertMoney(100, "Fanta");
vendingMachine.dispenseProduct();

/*
* Product has been dispensed so vending Machine changed the
* internal state to 'NoMoneyState'
*/

System.out.println("\nCurrent VendingMachine State : "
               + vendingMachine.getVendingMachineState().getClass().getName());

}

}

Output

Current VendingMachine State : NoMoneyState

Vending Machine cannot dispense product because money is not inserted and product is not selected...
100Rs has been inserted and Pepsi has been selected...
VendingMachine internal state has been moved to : HasMoneyState

Current VendingMachine State : HasMoneyState

Already Vending machine has money and product selected,So wait till it finish the current dispensing process ...
Vending Machine  dispensed the product ...
VendingMachine internal state has been moved to : NoMoneyState

Current VendingMachine State : NoMoneyState

See also:

  • State Design pattern - Introduction
  • State Design pattern - Real time example [ATM]
  • State Design pattern - Real time example [TV Remote]
  • State Design pattern - Real time example [Vending Machine]
  • State Design pattern - Real time example [Project]
  • State Design pattern - Class Diagram
  • State Design pattern - Implementation [ATM]
  • State Design pattern - Implementation [Project]
  • State Design pattern - Implementation [LED TV]
  • State Design pattern - Keypoints
  • All Design Patterns Links
  • Saturday, 25 January 2014

    State Design pattern - Real time example [Vending Machine]

    Master Practical Java Architecture & Design Patterns!

    Subscribe to Ram N Java for clean coding tutorials, GoF design patterns, and real-world system implementations!

    🔔 Subscribe to Ram N Java

    The Real-Time Vending Machine Problem

    A classic, intuitive way to understand behavioral design patterns is by examining how everyday machines operate. Consider a Vending Machine: depending on what state the machine is currently in, pressing the exact same button produces completely different outcomes:

    • No Coin State: Pressing an item button does nothing, alerting the user to insert money first.
    • Has Coin State: The machine accepts item selections and prepares to dispense goods.
    • Dispensing State: User inputs are temporarily locked while the mechanism delivers the item.
    • Sold Out State: All purchase requests are rejected, preventing coin acceptance or prompting maintenance.

    If you manage these conditions using procedural flags and nested if-else or switch blocks, adding a new action or state turns the code into an unmaintainable maze of conditional logic.

    How the State Pattern Models the Machine

    The State Design Pattern solves this complexity by turning every operational condition into an independent class:

    • State Interface: Declares actions supported across various states—such as insertCoin(), ejectCoin(), selectItem(), and dispense().
    • Concrete State Classes: Classes like NoCoinState, HasCoinState, and SoldOutState define what happens when each action is invoked, preventing invalid transitions and transitioning the context to the next valid state.
    • Context (Vending Machine): Maintains the active state reference, delegating all incoming user actions directly to the current state object.

    Key Architectural Benefits

    Structuring state-driven systems with the State pattern delivers immediate engineering benefits:

    • Eliminates Massive Conditionals: Replaces fragile if-else trees with clean polymorphic method calls.
    • Single Responsibility Principle: Keeps state validation, transitions, and business rules cleanly isolated in their own classes.
    • Open/Closed Principle: Adding new states (like CardPaymentState or MaintenanceState) requires no modifications to existing state classes.

    Related Tutorials from Ram N Java


    Click here to watch in Youtube : https://www.youtube.com/watch?v=Ole4PaPb3uQ

    Click the below Image to Enlarge

    State Design pattern - Real time example [Vending Machine]

















    See also:

  • State Design pattern - Introduction
  • State Design pattern - Real time example [ATM]
  • State Design pattern - Real time example [TV Remote]
  • State Design pattern - Real time example [Project]
  • State Design pattern - Class Diagram
  • State Design pattern - Implementation [ATM]
  • State Design pattern - Implementation [Vending Machine]
  • State Design pattern - Implementation [Project]
  • State Design pattern - Implementation [LED TV]
  • State Design pattern - Keypoints
  • All Design Patterns Links
  • Tutorials