Bird
Raised Fist0

Observer Pattern - Event-Driven Design and Decoupling Publisher from Subscriber

LLDeasyInterview freq: high
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
Subject abstract class

Subject holds a List<Observer> as private state and provides synchronized attach, detach, and notifyAll methods.

🎯 Tests understanding that Subject must be an abstract class (not interface) because it holds mutable state (observers list) and requires synchronized methods to avoid race conditions when modifying it.
public abstract class Subject {
    private final List<Observer> observers = new ArrayList<>();
    public synchronized void attach(Observer o) {
        observers.add(o);
    }
    public synchronized void detach(Observer o) {
        observers.remove(o);
    }
    public synchronized void notifyAllObservers(Event e) {
        for (Observer o : observers) {
            o.update(e);
        }
    }
}
ConcreteSubject composition and synchronization

ConcreteSubject extends Subject and composes an Event state with synchronized getter and setter to ensure thread-safe state changes.

🎯 Tests knowledge of composition lifecycle: ConcreteSubject owns Event instance lifecycle (composition), and synchronized setState prevents race conditions updating state before notifyAll.
public class ConcreteSubject extends Subject {
    private Event state;
    public synchronized Event getState() {
        return state;
    }
    public synchronized void setState(Event e) {
        this.state = e;
        notifyAllObservers(e);
    }
}
Observer interface and ConcreteObserver realization

Observer is an interface defining update(Event e) method; ConcreteObserver implements Observer and provides concrete update behavior.

🎯 Tests understanding that Observer is interface (no state) to allow multiple implementations (OCP), and ConcreteObserver realizes it with specific update logic.
public interface Observer {
    void update(Event e);
}
public class ConcreteObserver implements Observer {
    private String id;
    public ConcreteObserver(String id) {
        this.id = id;
    }
    @Override
    public void update(Event e) {
        System.out.println("Observer " + id + " received event: " + e);
    }
}
Template Method pattern in Subject notifyAllObservers

Subject defines notifyAllObservers as a synchronized method that iterates observers and calls their update method, enforcing a fixed notification algorithm.

🎯 Tests recognition of Template Method pattern: Subject controls notification sequence, subclasses/observers customize update behavior, enforcing decoupling and extensibility.
public abstract class Subject {
    // ...
    public synchronized void notifyAllObservers(Event e) {
        for (Observer o : observers) {
            o.update(e);
        }
    }
}
📐
Class Diagram
Class Diagram
       +----------------+
       | <<Abstract>>   |
       |    Subject     |
       +----------------+
       | - observers:   |
       |   List<Observer>|
       +----------------+
       | + attach(o):   |
       |   void [sync]  |
       | + detach(o):   |
       |   void [sync]  |
       | + notifyAll(): |
       |   void [sync]  |
       +----------------+
              │ extends
              │
       +----------------+
       | ConcreteSubj   |
       +----------------+
       | - state: Event |
       +----------------+
       | + getState():  |
       |   Event        |
       | + setState(e): |
       |   void [sync]  |
       +----------------+
              │
              │ composition
              │
       +----------------+
       | <<Interface>>  |
       |   Observer     |
       +----------------+
       | + update(e):   |
       |   void         |
       +----------------+
              │ realization
              │
       +----------------+
       |ConcreteObserver|
       +----------------+
       | - id: String   |
       +----------------+
       | + update(e):   |
       |   void         |
       +----------------+

This class diagram illustrates the Observer pattern in Java with key design decisions. Subject is an abstract class because it holds mutable state (the observers list) and requires synchronized methods to prevent race conditions when attaching, detaching, or notifying observers. ConcreteSubject composes an Event instance, owning its lifecycle, and synchronizes state changes to ensure thread safety before notifying observers. Observer is an interface to allow multiple implementations without shared state, enforcing the Open-Closed Principle. ConcreteObserver realizes Observer with specific update logic. The notifyAllObservers method in Subject exemplifies the Template Method pattern by defining the fixed notification algorithm while allowing subclasses to customize behavior via update. These Java-specific choices ensure thread safety, extensibility, and proper lifecycle management.

Primary Focus

✓ Abstract class vs Interface state + Realization vs Inheritance + Composition lifecycle + Template Method pattern

Practice

(1/5)
1. A class CarBuilder constructs a Car object step-by-step using methods like setEngine(), setWheels(), and finally build(). The Car constructor is private. Which design pattern is applied here and why is it the correct choice?
easy
A. Builder pattern, because it separates complex object construction from its representation, allowing stepwise creation.
B. Factory Method pattern, because it creates objects through inheritance and subclasses.
C. Prototype pattern, because it clones existing objects to create new ones efficiently.
D. Singleton pattern, because it ensures only one instance of Car exists.

Solution

  1. Step 1: Identify the construction process

    The class uses multiple setter methods to configure parts of the object before finalizing with build(), indicating stepwise construction.
  2. Step 2: Match pattern intent

    Builder pattern separates construction from representation, ideal for complex objects with many optional parts. Factory Method uses inheritance, Prototype clones objects, Singleton restricts instance count.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Stepwise object creation with private constructor -> Builder pattern [check]
Hint: Stepwise construction with private constructor -> Builder pattern [check]
Common Mistakes:
2. You are designing a Vehicle abstraction for a parking system. Should Vehicle be an abstract class or an interface if you need to store state like licensePlate and provide default behavior for getSize()? Why?
easy
A. Use an interface, because it allows multiple inheritance and state can be stored externally.
B. Use an interface, because interfaces can hold state and default methods provide behavior.
C. Use an abstract class, because it can hold instance variables and provide default method implementations.
D. Use an abstract class, because interfaces cannot define any methods.

Solution

  1. Step 1: Analyze state and behavior requirements

    The design requires storing state (licensePlate) and providing default behavior (getSize()).
  2. Step 2: Choose correct OOP construct

    Abstract classes can have instance variables and concrete methods with default behavior. Interfaces in Java 8+ can have default methods but cannot hold instance state. Therefore, abstract class fits the need.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Abstract class supports state and default behavior [check]
Hint: State needs abstract class; interfaces lack instance variables [check]
Common Mistakes:
3. In the Online Stock Brokerage system, the TradeManager class has a private constructor and a static synchronized getInstance() method. Which design pattern is applied here and why is this the correct choice?
easy
A. Prototype pattern, to clone existing trade instances for faster processing.
B. Factory pattern, because it controls object creation centrally for different trade types.
C. Builder pattern, to incrementally construct complex trade objects with validation.
D. Singleton pattern, to ensure only one instance manages all trades and avoid inconsistent state.

Solution

  1. Step 1: Identify the pattern from constructor and method

    The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single instance is created and accessed thread-safely.
  2. Step 2: Why Singleton fits this scenario

    TradeManager must coordinate all trades globally to maintain consistent state; multiple instances would cause conflicting trade states.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + synchronized getInstance() -> Singleton pattern [check]
Hint: Private constructor + static synchronized getInstance() -> Singleton [check]
Common Mistakes:
4. Given a Vehicle abstraction that requires both state (e.g., speed) and behavior (e.g., accelerate()), should Vehicle be an abstract class or an interface in Java, and why?
easy
A. Interface, because it allows multiple inheritance and can hold state variables.
B. Interface, because abstract classes cannot define method signatures without implementation.
C. Abstract class, because it can hold shared state and provide default behavior implementations.
D. Abstract class, because interfaces cannot have any methods related to behavior.

Solution

  1. Step 1: Analyze state and behavior requirements

    Since Vehicle needs to hold state like speed and provide default behavior like accelerate(), it requires fields and method implementations.
  2. Step 2: Choose between abstract class and interface

    Java interfaces cannot hold instance state (fields) prior to Java 8 default methods, and even then, no instance variables. Abstract classes can hold state and provide default method implementations, making them suitable here.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    State + default behavior -> abstract class, not interface [check]
Hint: State needs fields -> abstract class; interfaces lack instance variables [check]
Common Mistakes:
5. A class has a private constructor and a static synchronized getInstance() method returning a single instance. Which pattern is applied and why is this the CORRECT use case?
easy
A. Prototype pattern, because it clones existing instances to create new ones.
B. Factory Method pattern, because it controls object creation through a static method.
C. Builder pattern, because it constructs complex objects step-by-step.
D. Singleton pattern, because it ensures only one instance exists with controlled access.

Solution

  1. Step 1: Identify Singleton characteristics

    The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single shared instance with thread safety.
  2. Step 2: Eliminate other creational patterns

    Factory Method controls subclass instantiation, Builder separates construction from representation, and Prototype clones objects; none enforce a single instance.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + static synchronized getInstance() -> Singleton pattern [check]
Hint: Private constructor + static getInstance() = Singleton [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard