HuntExams Academy logo
JavaIntermediate#design-patterns

What is the Observer pattern?

Answer

A behavioral pattern where an object (subject) maintains a list of dependents (observers) and notifies them automatically of state changes, commonly used for event-driven systems like GUI listeners or pub/sub systems.

Example

interface Observer { void update(String event); }
class EventBus {
  List<Observer> observers = new ArrayList<>();
  void notifyAll(String event) { observers.forEach(o -> o.update(event)); }
}

Detailed explanation

The Observer pattern is a behavioral design pattern that defines a one-to-many dependency between objects. One object, called the subject or publisher, lets other objects, called observers or subscribers, register for notifications. When a relevant change occurs, the subject notifies its registered observers through a common interface. This matters because the subject can announce changes without knowing the concrete classes that react to them. For example, an order-status component could notify a UI panel, an audit logger, and a notification handler without directly depending on those implementations.

In Java, an observer interface might declare `void update(String event)`. The subject stores references to implementations in a `List<Observer>` and typically exposes methods such as `subscribe`, `unsubscribe`, and `publish`. Publishing traverses the collection and invokes `update(event)` on each observer. Your `EventBus` snippet demonstrates this notification loop, although it does not show registration, removal, or an actual state change. Its `notifyAll(String event)` method legally overloads the inherited, final `Object.notifyAll()` method; it does not override it. However, `publish` or `notifyObservers` is clearer because `Object.notifyAll()` has an unrelated thread-monitor purpose.

Observer notifications can use a push model, where the callback receives event data, or a pull model, where the observer queries the subject after receiving a change signal. The supplied loop is synchronous: callbacks execute on the publishing thread, so a slow observer delays subsequent observers and an uncaught exception interrupts delivery. Asynchronous execution requires an explicit mechanism, such as an executor, and introduces ordering, concurrency, and failure-handling decisions. Modifying the same `ArrayList` during iteration may also cause `ConcurrentModificationException`; snapshot iteration or a suitable concurrent collection can help.

Interviewers usually look for the subject-observer relationship, interface-based coupling, lifecycle management, and practical trade-offs rather than just the definition. Unsubscribing is important because retained observer references can prevent garbage collection. Observer also resembles publish-subscribe, but broker-based pub/sub commonly separates publishers and subscribers through channels rather than direct observer references. In modern Java, prefer custom listener interfaces or appropriate event APIs; the legacy `java.util.Observable` class and `java.util.Observer` interface have been deprecated since Java 9.

Key points to remember

  • Observer establishes a one-to-many relationship through a shared notification interface.
  • Subjects manage subscriptions and notify observers when relevant changes occur.
  • Push notifications carry data; pull notifications prompt observers to query state.
  • Direct callback loops are synchronous unless asynchronous dispatch is explicitly implemented.
  • Robust implementations address unsubscription, callback failures, and collection mutation.

Common mistakes candidates make

  • Assuming Observer automatically provides asynchronous, thread-safe, or reliable delivery.
  • Forgetting to remove observers, allowing subjects to retain unwanted references.
  • Confusing the example's notifyAll(String) overload with Object.notifyAll(), which wakes threads waiting on a monitor.

Likely follow-up questions

How is Observer different from publish-subscribe?

In a typical Observer implementation, the subject holds observer references and invokes their callbacks directly. Broker-based publish-subscribe routes messages through topics or channels, reducing direct knowledge between publishers and subscribers; terminology can overlap across libraries.

How would you make the example safer when subscriptions change during notification?

For read-heavy workloads, CopyOnWriteArrayList allows iteration over a stable snapshot, but makes subscription changes more expensive. Alternatively, copy the observer list under a lock and invoke callbacks outside that lock; neither approach alone makes observer state thread-safe.

What happens if an observer throws an exception?

In the supplied forEach loop, an unchecked exception propagates to the publisher and prevents remaining observers from receiving that event. If independent delivery is required, handle exceptions around each callback and report failures according to an explicit policy.

Interview tip: Explain the subject and observer roles first, walk through registration and notification, then mention one practical concern such as callback failures or unsubscription.

Related Interview Questions

1
JavaIntermediate#design-patterns

What is the Strategy pattern?

Open
2
JavaAdvanced#design-patterns

What is the difference between the Adapter and Decorator patterns?

Open
3
JavaAdvanced#design-patterns#oop

What is the difference between composition and inheritance, and why is 'favor composition over inheritance' recommended?

Open