🎲 State Design Pattern
The State Design Pattern is a behavioral pattern where:
-
An object’s behavior changes depending on its internal state.
-
Instead of using giant
if/elseorswitchstatements, each state is encapsulated in its own class. -
The object (called Context) delegates behavior to the current State
Escape Room Example Scenario
Section titled “Escape Room Example Scenario”Imagine a Door in your escape room:
-
A door can be Locked, Unlocked, or Open.
-
Depending on its state:
-
If Locked, you can’t open it.
-
If Unlocked, you can open it.
-
If Open, you can’t unlock it anymore.
-
We’ll model this with the State Pattern.
State Interface
Section titled “State Interface”// State interfacepublic interface DoorState { void unlock(Door door); void open(Door door); void lock(Door door);}Concrete States
Section titled “Concrete States”// Locked Statepublic class LockedState implements DoorState { @Override public void unlock(Door door) { System.out.println("You unlocked the door."); door.setState(new UnlockedState()); }
@Override public void open(Door door) { System.out.println("The door is locked. You can't open it."); }
@Override public void lock(Door door) { System.out.println("The door is already locked."); }}
// Unlocked Statepublic class UnlockedState implements DoorState { @Override public void unlock(Door door) { System.out.println("The door is already unlocked."); }
@Override public void open(Door door) { System.out.println("You opened the door."); door.setState(new OpenState()); }
@Override public void lock(Door door) { System.out.println("You locked the door again."); door.setState(new LockedState()); }}
// Open Statepublic class OpenState implements DoorState { @Override public void unlock(Door door) { System.out.println("The door is already open."); }
@Override public void open(Door door) { System.out.println("The door is already open."); }
@Override public void lock(Door door) { System.out.println("You closed and locked the door."); door.setState(new LockedState()); }}Context Class
Section titled “Context Class”public class Door { private DoorState state;
public Door() { // Start with locked door this.state = new LockedState(); }
public void setState(DoorState state) { this.state = state; }
public void unlock() { state.unlock(this); }
public void open() { state.open(this); }
public void lock() { state.lock(this); }}Using the State Pattern in the Game
Section titled “Using the State Pattern in the Game”public class EscapeRoomGame { public static void main(String[] args) { Door door = new Door();
door.open(); // "The door is locked. You can't open it." door.unlock(); // "You unlocked the door." door.open(); // "You opened the door." door.lock(); // "You closed and locked the door." }}Sample Output
Section titled “Sample Output”The door is locked. You can't open it.You unlocked the door.You opened the door.You closed and locked the door.Why is this Useful in a Game?
Section titled “Why is this Useful in a Game?”-
Encapsulation of behavior: Each state has its own logic → no giant
if-else. -
Dynamic behavior: The same method call (
door.open()) does different things depending on state. -
Extensibility: Adding a new state (e.g., “BrokenDoorState”) is easy.
Next Step Ideas 💡
Section titled “Next Step Ideas 💡”-
Add a Puzzle State (e.g., unsolved, partially solved, solved).
-
Add a Game State (e.g., playing, paused, game over).
-
Combine with Observer Pattern so state changes notify other parts of the game.
✅ Key Takeaway:
The State Pattern is like giving each state its own brain. Instead of your context object managing tons of conditions, it simply asks its current state: “What do I do now?”