State Pattern
Pros
- Allows changing of an object's behavior depending on its state at run-time
- Removes the need for repetitive conditionals by moving state behavior into their own class
Cons
- Increases complexity which may be a bad thing if there are only a few simple state changes
Example Explanation
GachaMachine
IGachaState - interface that encapsulates state behavior of the GachaMachine
GachaGivingPrize/GachaWithCoin/GachaNoCoin - concrete implementations of IGachaState

class Main {
public static void main(String[] args) {
GachaMachine machine = new GachaMachine();
machine.displayState(); //Current State: NoCoinState
machine.givePrize(); //No coin inserted.
machine.pressButton(); //No coin inserted.
machine.insertCoin(); //Coin inserted..
//--changing state--
machine.displayState(); //Current State: WithCoinState
machine.insertCoin(); //Coin already inserted.
machine.givePrize(); //Press button for prize.
machine.pressButton(); //Button pressed..
//--changing state--
machine.displayState(); //Current State: GivingPrizeState
machine.insertCoin(); //Coin already inserted.
machine.pressButton(); //Button already pressed.
machine.givePrize(); //Giving prize..
//--changing state--
machine.displayState(); //Current State: NoCoinState
}
}
interface IGachaState{
public void insertCoin();
public void pressButton();
public void givePrize();
}
class GachaNoCoin implements IGachaState{
private GachaMachine machine;
public GachaNoCoin(GachaMachine machine){
this.machine = machine;
}
@Override
public void insertCoin(){
System.out.println("Coin inserted..");
machine.setState( machine.getWithCoinState() );
}
@Override
public void pressButton(){
System.out.println("No coin inserted.");
}
@Override
public void givePrize(){
System.out.println("No coin inserted.");
}
@Override
public String toString(){ return "NoCoinState"; }
}
class GachaWithCoin implements IGachaState{
private GachaMachine machine;
public GachaWithCoin(GachaMachine machine){
this.machine = machine;
}
@Override
public void insertCoin(){
System.out.println("Coin already inserted.");
}
@Override
public void pressButton(){
System.out.println("Button pressed..");
machine.setState( machine.getGivingPrizeState() );
}
@Override
public void givePrize(){
System.out.println("Press button for prize.");
}
@Override
public String toString(){ return "WithCoinState"; }
}
class GachaGivingPrize implements IGachaState{
private GachaMachine machine;
public GachaGivingPrize(GachaMachine machine){
this.machine = machine;
}
@Override
public void insertCoin(){
System.out.println("Coin already inserted.");
}
@Override
public void pressButton(){
System.out.println("Button already pressed.");
}
@Override
public void givePrize(){
System.out.println("Giving prize..");
machine.setState( machine.getNoCoinState() );
}
@Override
public String toString(){ return "GivingPrizeState"; }
}
class GachaMachine implements IGachaState{
private IGachaState noCoinState;
private IGachaState withCoinState;
private IGachaState givingPrizeState;
private IGachaState state;
public GachaMachine(){
this.noCoinState = new GachaNoCoin(this);
this.withCoinState = new GachaWithCoin(this);
this.givingPrizeState = new GachaGivingPrize(this);
this.state = noCoinState;
}
public void setState(IGachaState state){
this.state = state;
System.out.println("--changing state--");
}
@Override
public void insertCoin(){
state.insertCoin();
}
@Override
public void pressButton(){
state.pressButton();
}
@Override
public void givePrize(){
state.givePrize();
}
public void displayState(){ System.out.println("Current State: "+state.toString()); };
public IGachaState getNoCoinState(){ return noCoinState; }
public IGachaState getWithCoinState(){ return withCoinState; }
public IGachaState getGivingPrizeState(){ return givingPrizeState; }
}
Extra Resources
https://springframework.guru/gang-of-four-design-patterns/state-pattern/