🎰
Machine & Device Design

Vending Machine

State Pattern Ka Best Example
💡 Vending machine EK SAKHT DUKAANDAR hai jo ORDER follow karta hai — pehle paise, phir saamaan, phir chhutta. Beech mein koi step chhodo to wo saaf mana kar deta hai.

Ye problem SPECIFICALLY State pattern test karne ke liye poochi jaati hai. States hain: IDLE → HAS_MONEY → DISPENSING → OUT_OF_STOCK. Har state batati hai ki us waqt kaunsa action VALID hai. Bina State pattern ke ye code nested if-else ka jungle ban jaata hai.

Do cheezein hamesha poochi jaati hain — CHANGE (chhutta) aur REFUND. Change calculation ek chhota greedy coin problem hai (bade denomination se shuru), aur cancel karne par poora refund milna chahiye. Inventory ko bhi thread-safe rakho: do log aakhri item ek saath na le lein.

interface VendingState {
  void insertCoin(VendingMachine m, Coin c);
  void selectItem(VendingMachine m, String code);
  void dispense(VendingMachine m);
}

class IdleState implements VendingState {
  public void insertCoin(VendingMachine m, Coin c) {
    m.addBalance(c.getValue());
    m.setState(new HasMoneyState());
  }
  public void selectItem(VendingMachine m, String code) {
    throw new IllegalStateException("Pehle paise daaliye");
  }
  public void dispense(VendingMachine m) {
    throw new IllegalStateException("Kuch select nahi kiya");
  }
}
🎰
Vending machine EK SAKHT DUKAANDAR hai jo ORDER follow karta hai — pehle paise, phir saamaan, phir chhutta. Beech mein koi step chhodo to wo saaf mana kar deta hai.
1 / 2
⚡ Quick Recap
  • States: IDLE → HAS_MONEY → DISPENSING → OUT_OF_STOCK
  • Har state khud decide kare kaunsa action valid hai — nested if-else nahi
  • Change (greedy) aur refund dono handle karo, inventory thread-safe rakho
Is page mein (2 subtopics)

Change greedy se nikalta hai — sabse bade coin se shuru karo, jitne aa sakein utne do, bacha hua chhote coin se. Indian/US denominations ke liye greedy hamesha optimal hai.

Par asli jaal ye hai: greedy tab fail karta hai jab machine ke paas wo coin HI NA HO. Isliye transaction START hone se PEHLE check karo ki change dena possible hai ya nahi. Item de dene ke baad "chhutta nahi hai" bolna sabse bura outcome hai.

Optional<List<Coin>> computeChange(int amount) {
  List<Coin> result = new ArrayList<>();
  for (Coin c : Coin.descending()) {
    while (amount >= c.value() && inventory.has(c)) {
      amount -= c.value(); result.add(c); inventory.reserve(c);
    }
  }
  return amount == 0 ? Optional.of(result) : Optional.empty();  // pehle hi reject
}

Ek hi machine par ek user hota hai, isliye log concurrency ignore kar dete hain. Par interviewer aksar isko MULTI-OUTLET ya NETWORKED machine mein badal deta hai — tab do requests ek hi aakhri item par aa sakti hain.

Solution wahi hai: check aur deduct atomic. AtomicInteger ka compareAndSet, ya synchronized block. Aur item khatam hone par state OUT_OF_STOCK par chali jaani chahiye taaki wahi item dobara select na ho sake.

💡Tip: Refund flow bhi state machine ka hissa hai — kisi bhi state se CANCEL par IDLE mein wapas jaana chahiye aur poora balance return hona chahiye.