An object changes its behavior when its internal state changes. Without State, you get giant if-else chains checking state in every method. With State, each state is a class with its own behavior. Adding a new state means one new class, not modifying every method.
class VendingMachine {
String state = "IDLE";
void insertCoin() {
if (state.equals("IDLE")) { state = "HAS_MONEY"; }
else if (state.equals("HAS_MONEY")) { /* already has money */ }
else if (state.equals("DISPENSING")) { /* wait */ }
}
void selectItem(String item) {
if (state.equals("IDLE")) { /* no money */ }
else if (state.equals("HAS_MONEY")) { state = "DISPENSING"; }
else if (state.equals("DISPENSING")) { /* already dispensing */ }
}
// Every method needs the same if-else chain.
// Adding "MAINTENANCE" state means editing every method.
}// ─── EXAMPLE 1 ──────────────────────────────────────────────────────────────
// WHAT WE ARE IMPLEMENTING:
// A vending machine controlling item selection and coin insertion
// transitions.
//
// WHERE THE STATE FITS IN:
// VendingMachineState is the State interface. HasCoinState and NoCoinState
// represent Concrete States. VendingMachine acts as the Context tracking
// states.
// ────────────────────────────────────────────────────────────────────────────
// --- State interface ---
interface VendingMachineState {
void insertCoin(VendingMachine vm);
void selectItem(VendingMachine vm, String item);
void dispense(VendingMachine vm);
}
// --- Context ---
class VendingMachine {
private VendingMachineState state;
private int balance = 0;
public VendingMachine() {
state = new IdleState();
}
void setState(VendingMachineState state) {
System.out.println(" [State] " + this.state.getClass().getSimpleName() + " -> " + state.getClass().getSimpleName());
this.state = state;
}
void setBalance(int b) { this.balance = b; }
int getBalance() { return balance; }
public void insertCoin() { state.insertCoin(this); }
public void selectItem(String item) { state.selectItem(this, item); }
public void dispense() { state.dispense(this); }
}
// --- Concrete states ---
class IdleState implements VendingMachineState {
public void insertCoin(VendingMachine vm) {
System.out.println(" Coin inserted: $5");
vm.setBalance(5);
vm.setState(new HasMoneyState());
}
public void selectItem(VendingMachine vm, String item) {
System.out.println(" Insert coin first");
}
public void dispense(VendingMachine vm) {
System.out.println(" Insert coin first");
}
}
class HasMoneyState implements VendingMachineState {
public void insertCoin(VendingMachine vm) {
System.out.println(" Coin already inserted. Balance: $" + vm.getBalance());
}
public void selectItem(VendingMachine vm, String item) {
System.out.println(" Item selected: " + item);
if (vm.getBalance() >= 5) {
vm.setState(new DispensingState());
} else {
System.out.println(" Insufficient balance");
}
}
public void dispense(VendingMachine vm) {
System.out.println(" Select item first");
}
}
class DispensingState implements VendingMachineState {
public void insertCoin(VendingMachine vm) {
System.out.println(" Dispensing in progress");
}
public void selectItem(VendingMachine vm, String item) {
System.out.println(" Dispensing in progress");
}
public void dispense(VendingMachine vm) {
System.out.println(" Dispensing item... Enjoy!");
vm.setBalance(0);
vm.setState(new IdleState());
}
}
public class Main {
public static void main(String[] args) {
VendingMachine vm = new VendingMachine();
// Full flow
vm.insertCoin(); // Idle -> HasMoney
vm.selectItem("Coke"); // HasMoney -> Dispensing
vm.dispense(); // Dispensing -> Idle
// Edge cases
vm.dispense(); // Idle -> "Insert coin first"
vm.selectItem("Chips"); // Idle -> "Insert coin first"
}
}