AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

04 Vending machine / Lesson 1 of 1

Vending machine

12 min · +10 XP · 2 exercises · 4 questions

Read the text12 min
Exercises0/2
Quiz4 q

Quick answer

How do you implement a vending machine with the State pattern in Java?

Give the machine a State field and an interface with one method per event: insert, select, cancel. Idle, HasMoney and OutOfStock each implement it, answer the event their own way and move the machine to the next state. The machine itself holds only the balance and the items, and delegates every event to its current state.

The textbook case for the State pattern: a coin means start a sale in one state, add to the balance in another and give it back in a third. The full design, with a sequence diagram and code in four languages, is the note Design a Vending Machine.

One class per state

  • VendingMachine holds the items (code, name, price, stock), the balance and the current state — and no if-chain on a status.
  • interface State { insert, select, cancel }, implemented by Idle, HasMoney and OutOfStock.
  • Each state answers the event and decides the transition: machine.move(next).
  • States hold no data of their own, so one shared instance of each is enough.
One slot of chips through the vending machine's states
A1 chips 15, stock 1: SELECT, INSERT 10, SELECT, INSERT 10, SELECT, INSERT 5

Three states, each a class answering every event. The arrows are the only ways between them, and each is taken by a state's own code calling machine.move.

0:01 / 0:20Step 1 of 7
Transcript · 7 steps
INSERTSELECTCANCEL
Idleadd, → HasMoney"insert coins first"nothing to return
HasMoneyaddsell if paid, → Idle or OutOfStockrefund, → Idle
OutOfStockreturn the coin"sold out"nothing to return

A coin the machine does not accept (only 1, 2, 5 and 10) is rejected before any state sees it.

Making change

Making change: greedy, and where a real coin box breaks it
change 19 from 10, 5, 2, 1; then 6 from a box of one 5 and three 2s

The balance is 19 more than the price. Greedy change looks for the largest coin that still fits the amount left, and repeats until nothing is left.

0:01 / 0:19Step 1 of 7
Transcript · 7 steps
  • Greedy: the largest coin that fits, repeat. For 10, 5, 2, 1 it gives the fewest coins.
  • It is not optimal for every coin set, and a real box holds a limited number of each coin: then greedy can fail where an answer exists (6 from one 5 and three 2s is 2 + 2 + 2). The checkpoint makes you handle that.

Sold out, twice

  • A slot with stock 0 refuses its selection; the balance stays.
  • When every slot is empty, the machine is in OutOfStock and hands coins straight back. REFILL moves it back to Idle.

The traps

  • if (state == HAS_MONEY) … else if … in every method: adding a state edits them all.
  • Changing state from outside the states: transitions scattered over the machine are the if-chain again.
  • Forgetting the balance on a refused selection: an underpaid or sold-out choice keeps the money in.

Common questions

Why not use a status field and if-else for a vending machine?

Every event would need a branch for every status, so adding a state such as Maintenance edits every method. With the State pattern each state is one class answering every event, and a new state is a new class plus the transitions into it.

How does a vending machine give change?

It takes the largest coin that fits the remaining amount, again and again. For the coins 10, 5, 2 and 1 this greedy rule gives the fewest coins, but not for every coin set; with only the coins actually in the box, a search over combinations is needed.

What happens when a vending machine is out of stock?

When the last item is sold the machine moves to an OutOfStock state, which returns any coin inserted at once and refuses every selection. Restocking a slot moves it back to Idle.

Should Dispensing be a separate state?

In a real machine yes, because coins and buttons can arrive while the motor turns, and Dispensing must refuse them. In a single-threaded program the sale finishes inside one call, so the exercises fold it into the selection and go straight to Idle or OutOfStock.

Mark as readSign in to keep your place.

Vending Machine in Java: State Pattern, Change and Sold Out

Code a vending machine in Java with the State pattern: Idle, HasMoney and OutOfStock classes, greedy change from 10, 5, 2 and 1, cancel refunds and restocking.

How do you implement a vending machine with the State pattern in Java?

Give the machine a State field and an interface with one method per event: insert, select, cancel. Idle, HasMoney and OutOfStock each implement it, answer the event their own way and move the machine to the next state. The machine itself holds only the balance and the items, and delegates every event to its current state.

Lesson

The textbook case for the State pattern: a coin means start a sale in one state, add to the balance in another and give it back in a third. The full design, with a sequence diagram and code in four languages, is the note Design a Vending Machine.

One class per state

  • VendingMachine holds the items (code, name, price, stock), the balance and the current state — and no if-chain on a status.
  • interface State { insert, select, cancel }, implemented by Idle, HasMoney and OutOfStock.
  • Each state answers the event and decides the transition: machine.move(next).
  • States hold no data of their own, so one shared instance of each is enough.
coinlast soldrefillsale, cancelIdleHasMoneyOutOfStockslot A1: chips, price 15, stock 0 balance 0INSERT 5→ sold out, returned 5
One slot of chips through the vending machine's states. Example: A1 chips 15, stock 1: SELECT, INSERT 10, SELECT, INSERT 10, SELECT, INSERT 5
  1. Three states, each a class answering every event. The arrows are the only ways between them, and each is taken by a state's own code calling machine.move.
  2. Selecting in Idle starts nothing: Idle.select answers that coins come first, and the machine stays where it is.
  3. A coin is the one event that leaves Idle: Idle.insert adds 10 to the balance and moves the machine to HasMoney.
  4. The chips cost 15 and the balance is 10: HasMoney refuses the selection, keeps the money and stays in HasMoney.
  5. In HasMoney a coin only raises the balance, to 20. The same INSERT event, a different class answering it.
  6. HasMoney.select finds the price of 15 covered, drops the chips with change 5 and, as that was the last one, moves to OutOfStock rather than Idle.
  7. OutOfStock cannot finish a sale, so it never starts one: OutOfStock.insert hands the coin straight back.
INSERTSELECTCANCEL
Idleadd, → HasMoney"insert coins first"nothing to return
HasMoneyaddsell if paid, → Idle or OutOfStockrefund, → Idle
OutOfStockreturn the coin"sold out"nothing to return

A coin the machine does not accept (only 1, 2, 5 and 10) is rejected before any state sees it.

Making change

coins in the box10×05×12×31×0paid222paid 2+2+2, left 0
Making change: greedy, and where a real coin box breaks it. Example: change 19 from 10, 5, 2, 1; then 6 from a box of one 5 and three 2s
  1. The balance is 19 more than the price. Greedy change looks for the largest coin that still fits the amount left, and repeats until nothing is left.
  2. 10 fits 19, and it is the largest coin, so it goes first, leaving 9.
  3. 9 is left, so 10 no longer fits: the largest coin that does is 5, leaving 4.
  4. 4 is left, so 10 and 5 no longer fit: the largest coin that does is 2, leaving 2.
  5. A last 2 pays it off: 10 + 5 + 2 + 2 = 19 in 4 coins. For 10, 5, 2, 1 no shorter answer exists — this coin set is canonical.
  6. Now the box holds one 5, three 2s and no 1s, and 6 is due. Greedy takes the 5 and is stuck with 1 to pay: there is no 1 left in the box.
  7. Trying every count of each coin finds 2 + 2 + 2: three coins the box really holds. With limited coins, search the combinations — or refuse the sale before dispensing.
  • Greedy: the largest coin that fits, repeat. For 10, 5, 2, 1 it gives the fewest coins.
  • It is not optimal for every coin set, and a real box holds a limited number of each coin: then greedy can fail where an answer exists (6 from one 5 and three 2s is 2 + 2 + 2). The checkpoint makes you handle that.

Sold out, twice

  • A slot with stock 0 refuses its selection; the balance stays.
  • When every slot is empty, the machine is in OutOfStock and hands coins straight back. REFILL moves it back to Idle.

The traps

  • if (state == HAS_MONEY) … else if … in every method: adding a state edits them all.
  • Changing state from outside the states: transitions scattered over the machine are the if-chain again.
  • Forgetting the balance on a refused selection: an underpaid or sold-out choice keeps the money in.

Common questions

Why not use a status field and if-else for a vending machine?

Every event would need a branch for every status, so adding a state such as Maintenance edits every method. With the State pattern each state is one class answering every event, and a new state is a new class plus the transitions into it.

How does a vending machine give change?

It takes the largest coin that fits the remaining amount, again and again. For the coins 10, 5, 2 and 1 this greedy rule gives the fewest coins, but not for every coin set; with only the coins actually in the box, a search over combinations is needed.

What happens when a vending machine is out of stock?

When the last item is sold the machine moves to an OutOfStock state, which returns any coin inserted at once and refuses every selection. Restocking a slot moves it back to Idle.

Should Dispensing be a separate state?

In a real machine yes, because coins and buttons can arrive while the motor turns, and Dispensing must refuse them. In a single-threaded program the sale finishes inside one call, so the exercises fold it into the selection and go straight to Idle or OutOfStock.

Exercises

The state machine

Model a vending machine with the State pattern: a State interface implemented by Idle, HasMoney and OutOfStock, and a machine that hands every event to its current state. The first line is the number of slots n; each of the next n lines is <code> <name> <price> <stock> (single words, whole numbers). The machine accepts coins of 1, 2, 5 and 10. Then events, one per line:

CommandPrints
INSERT <coin>not 1, 2, 5 or 10: rejected <coin> (in any state). Idle → balance <b> and HasMoney; HasMoney → balance <b>; OutOfStock → sold out, returned <coin>
SELECT <code>Idle → insert coins first; OutOfStock → sold out; HasMoney → error: no slot <code>, <code> is sold out, need <k> more, or dispensed <name>, change <coins> / dispensed <name>, no change
CANCELHasMoney → returned <coins> and Idle; otherwise nothing to return
STATEIdle, HasMoney or OutOfStock
anything elseerror: unknown command <WORD>

The machine starts in Idle, or in OutOfStock if every slot is empty. After a sale it moves to Idle — or to OutOfStock when that sale emptied the last slot. A refused selection keeps the balance. Change and refunds are paid greedily — the largest coin that fits, again and again — and printed largest first joined with + (10+5+2+2).

Inventory and restocking

Extend the state machine with inventory. The first line is the number of slots n; each of the next n lines is <code> <name> <price> <stock> (single words, whole numbers). The machine accepts coins of 1, 2, 5 and 10. Every event of the first program works as before:

CommandPrints
INSERT <coin>not 1, 2, 5 or 10: rejected <coin> (in any state). Idle → balance <b> and HasMoney; HasMoney → balance <b>; OutOfStock → sold out, returned <coin>
SELECT <code>Idle → insert coins first; OutOfStock → sold out; HasMoney → error: no slot <code>, <code> is sold out, need <k> more, or dispensed <name>, change <coins> / dispensed <name>, no change
CANCELHasMoney → returned <coins> and Idle; otherwise nothing to return
STATEIdle, HasMoney or OutOfStock

and three maintenance commands are added — they work in any state:

CommandPrints
REFILL <code> <count><code> stock <new stock>, or error: no slot <code>. In OutOfStock, the machine moves to Idle once any slot has stock again (a refill of 0 keeps it OutOfStock); in other states the state is kept.
REPORTone line per slot, in code order: <code> <name>: stock <s>, sold <k>
TOTALrevenue <sum of the prices of every item sold>
anything elseerror: unknown command <WORD>

The machine starts in Idle, or in OutOfStock if every slot is empty. After a sale it moves to Idle — or to OutOfStock when that sale emptied the last slot. A refused selection keeps the balance. Change and refunds are greedy, printed largest first joined with +.

In this module: Vending machine

← Checkpoint — Parking lot · Checkpoint — Vending machine →