Skip to content

🔔 Observer Design Pattern

The Observer Pattern is a behavioral design pattern where:

  • An object (subject) maintains a list of dependents (observers).

  • When the subject’s state changes, it notifies all observers automatically.

Think of it as a subscription system:

  • Subject = publisher (e.g., a puzzle or a timer in the escape room).

  • Observers = subscribers (e.g., doors, traps, or players listening for changes).


In an escape room:

  • Solving a puzzle (subject) might trigger multiple reactions:

    • A door opens.

    • A light turns on.

    • A trap is disabled.


// Observer interface
public interface Observer {
void update(String event);
}


// Subject interface
public interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String event);
}


import java.util.ArrayList;
import java.util.List;
public class Puzzle implements Subject {
private List<Observer> observers = new ArrayList<>();
private boolean solved = false;
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String event) {
for (Observer observer : observers) {
observer.update(event);
}
}
public void solvePuzzle() {
solved = true;
System.out.println("Puzzle solved!");
notifyObservers("Puzzle solved");
}
public boolean isSolved() {
return solved;
}
}


import java.util.ArrayList;
import java.util.List;
public class Puzzle implements Subject {
private List<Observer> observers = new ArrayList<>();
private boolean solved = false;
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String event) {
for (Observer observer : observers) {
observer.update(event);
}
}
public void solvePuzzle() {
solved = true;
System.out.println("Puzzle solved!");
notifyObservers("Puzzle solved");
}
public boolean isSolved() {
return solved;
}
}


public class EscapeRoomGame {
public static void main(String[] args) {
Puzzle puzzle = new Puzzle();
// Create observers
Door door = new Door();
Light light = new Light();
Trap trap = new Trap();
// Subscribe them to puzzle events
puzzle.addObserver(door);
puzzle.addObserver(light);
puzzle.addObserver(trap);
// Solve puzzle
puzzle.solvePuzzle();
// Output:
// Puzzle solved!
// The door creaks open...
// The lights flicker on!
// The trap mechanism is disabled.
}
}

  • Loose coupling: Puzzle doesn’t need to know what happens after solving — it just notifies.

  • Flexibility: You can add/remove observers at runtime.

  • Reusability: Same observer (e.g., Light) could listen to different subjects (multiple puzzles).


  • Add a Timer subject that notifies observers (e.g., “Time’s up!” → lock doors).

  • Allow players to be observers (notified when something changes).

  • Combine with Strategy Pattern so puzzles have different solving strategies and can notify observers when solved.


Key Takeaway:
The Observer Pattern makes your game reactive. Solving one puzzle can ripple through the room, triggering doors, lights, or traps without hardcoding dependencies.