Vending Machine
Idea
The key point for this question is that you should recognize the states switching process. Essentially, it's a thinking about state pattern.
Four States for a vending machine:
- Empty (Nothing in vending machine) 无商品
- Coin Inserted 已投币
- No Coin Inserted 未投币
- Dispense a merchandise 出售商品
You can use integer to represent state like this:
// 已投币
private final static int HAS_MONEY = 0;
// 未投币
private final static int NO_MONEY = 1;
// 售出商品
private final static int SOLD = 2;
// 商品售罄
private final static int SOLD_OUT = 3;
BUT it'd be better to use classes with designed inheritance relationship, like following
// 已投币
State coninInsertedState = new CoinInsertedState(this);
// 商品售罄
State emptyState = new EmptyState(this);
// 未投币
State noCoinInsertedState = new NoCoinInsertedState(this);
// 售出商品
State dispensingState = new DispensingState(this);
Code
First We should think about state interface:
State.java
// State interface
import statepattern.exception.MachineWarning;
public interface State {
public void insertCoin()throws MachineWarning;
public void pressButton()throws MachineWarning;
public void dispense()throws MachineWarning;
}
Concrete States implementations
ConinInsertedState.java
// Inserted Coin state
package statepattern;
import statepattern.exception.MachineWarning;
public class CoinInsertedState implements State{
VendingMachine machine =null;
public CoinInsertedState(VendingMachine machine) {
this.machine = machine;
}
public void insertCoin() throws MachineWarning{
throw new MachineWarning("Coin is already inserted.");
}
public void dispense() throws MachineWarning{
throw new MachineWarning("Dispense button is not pressed.");
}
public void pressButton() throws MachineWarning{
machine.setMachineState(machine.getDispensingState());
}
}
DispensingState.java
// Dispensing Merchandise
package statepattern;
import statepattern.exception.MachineWarning;
public class DispensingState implements State{
VendingMachine machine ;
DispensingState(VendingMachine machine) {
this.machine = machine;
}
public void insertCoin() throws MachineWarning {
throw new MachineWarning("wait ... previous order is processing");
}
public void pressButton() throws MachineWarning {
throw new MachineWarning("wait ... previous order is processing");
}
public void dispense() throws MachineWarning {
machine.setMachineState(machine.getNoCoinInsertedState());
}
}
EmptyState.java
// Nothing in machine (Empty)
package statepattern;
import statepattern.exception.MachineWarning;
public class EmptyState implements State{
VendingMachine machine;
public EmptyState(VendingMachine machine) {
this.machine = machine;
}
public void insertCoin() throws MachineWarning{
throw new MachineWarning("Can not process the request");
}
public void pressButton() throws MachineWarning{
throw new MachineWarning("Invalid Action");
}
public void dispense() throws MachineWarning{
throw new MachineWarning("Invalid Action");
}
}
NoCoinInsertedState.java
// No coin inserted
package statepattern;
import statepattern.exception.MachineWarning;
public class NoCoinInsertedState implements State{
VendingMachine machine;
public NoCoinInsertedState(VendingMachine machine) {
this.machine = machine;
}
public void insertCoin() throws MachineWarning{
if (!machine.isEmpty()) {
machine.setMachineState(machine.getConinInsertedState());
}
else {
throw new MachineWarning("Can not process request .. Machine is out of stock");
}
}
public void pressButton() throws MachineWarning{
throw new MachineWarning("No coin inserted ..");
}
public void dispense() throws MachineWarning{
throw new MachineWarning("Invalid Operation");
}
}
Then, we have to think about how to structure of vending machine object.
VendingMachine.java
package statepattern;
import statepattern.exception.MachineWarning;
public class VendingMachine {
// declare
State coninInsertedState = new CoinInsertedState(this);
State emptyState = new EmptyState(this);
State noCoinInsertedState = new NoCoinInsertedState(this);
State dispensingState = new DispensingState(this);
State machineState = null;
int capacity = 0;
public VendingMachine() {
machineState = noCoinInsertedState;
}
public void reFill(int count) {
capacity += count;
machineState = noCoinInsertedState;
}
/**
* Two Actions performed by MAchine
*/
public void insertCoin() throws MachineWarning {
machineState.insertCoin();
}
public void pressButton() throws MachineWarning {
machineState.pressButton();
machineState.dispense();
capacity--;
}
public boolean isEmpty(){
if(capacity<=0)
return true;
else
return false;
}
public void setMachineState(State machineState) {
this.machineState = machineState;
}
public State getMachineState() {
return machineState;
}
public void setConinInsertedState(State coninInsertedState) {
this.coninInsertedState = coninInsertedState;
}
public State getConinInsertedState() {
return coninInsertedState;
}
public void setEmptyState(State emptyState) {
this.emptyState = emptyState;
}
public State getEmptyState() {
return emptyState;
}
public void setNoCoinInsertedState(State noCoinInsertedState) {
this.noCoinInsertedState = noCoinInsertedState;
}
public State getNoCoinInsertedState() {
return noCoinInsertedState;
}
public void setDispensingState(State dispensingState) {
this.dispensingState = dispensingState;
}
public State getDispensingState() {
return dispensingState;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public int getCapacity() {
return capacity;
}
}