Skip to main content

Command Palette

Search for a command to run...

Observer Design Pattern

Updated
•4 min read•View as Markdown
Observer Design Pattern
S

Campus Maven at RiseIn Postman Student Expert Web Developer and Blockchain enthusiast

Why Observer Pattern Exists

In real systems, objects often depend on other objects’ state changes.

Examples:

  • When stock price changes → update dashboards

  • When order is placed → send email + SMS + update inventory

  • When user registers → send welcome email

  • When payment succeeds → trigger receipt + analytics + notification

If we tightly couple everything like this:

orderService.placeOrder();
emailService.sendEmail();
smsService.sendSms();
analyticsService.track();

Your system becomes rigid and hard to extend.

Observer Pattern solves this.


What is Observer Pattern?

Observer Pattern defines:

A one-to-many dependency where when one object changes state, all its dependents are notified automatically.

In simple terms:

One object (Subject) maintains a list of observers.

When something changes, it informs all observers.


Real Backend Scenario

Let’s model an Order System.

When an order is placed:

  • Email service should be notified

  • SMS service should be notified

  • Inventory service should update stock

Instead of hardcoding calls,

we let services subscribe.


Clean Java Implementation

Step 1 — Observer Interface

public interface OrderObserver {
    void update(String orderId);
}

This ensures all observers respond consistently.

Step 2 — Concrete Observers

Email Service

public class EmailService implements OrderObserver {

    @Override
    public void update(String orderId) {
        System.out.println("Email sent for order: " + orderId);
    }
}

SMS Service

public class SmsService implements OrderObserver {

    @Override
    public void update(String orderId) {
        System.out.println("SMS sent for order: " + orderId);
    }
}

Inventory Service

public class InventoryService implements OrderObserver {

    @Override
    public void update(String orderId) {
        System.out.println("Inventory updated for order: " + orderId);
    }
}

Each class focuses only on its responsibility.


Step 3 — Subject Interface

import java.util.List;

public interface OrderSubject {
    void addObserver(OrderObserver observer);
    void removeObserver(OrderObserver observer);
    void notifyObservers(String orderId);
}

Step 4 — Concrete Subject

import java.util.ArrayList;
import java.util.List;

public class OrderService implements OrderSubject {

    private final List<OrderObserver> observers = new ArrayList<>();

    @Override
    public void addObserver(OrderObserver observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(OrderObserver observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(String orderId) {
        for (OrderObserver observer : observers) {
            observer.update(orderId);
        }
    }

    public void placeOrder(String orderId) {
        System.out.println("Order placed: " + orderId);
        notifyObservers(orderId);
    }
}

Notice:

  • OrderService doesn’t know about EmailService or SmsService directly.

  • It only knows about the interface.

That’s loose coupling.


Step 5 — Client Code

public class Main {
    public static void main(String[] args) {

        OrderService orderService = new OrderService();

        orderService.addObserver(new EmailService());
        orderService.addObserver(new SmsService());
        orderService.addObserver(new InventoryService());

        orderService.placeOrder("ORD123");
    }
}

Output:

Order placed: ORD123
Email sent for order: ORD123
SMS sent for order: ORD123
Inventory updated for order: ORD123

Where Observer is Used in Real Systems

  • Spring Application Events

  • Event-driven architectures

  • Message brokers (conceptually similar)

  • UI frameworks (listeners)

  • Microservices event publishing

  • Java’s EventListener mechanisms

Strong interview point:

Observer is foundational for event-driven design.


When NOT to Use Observer

Avoid when:

  • Only one dependent exists

  • Notification order is critical and complex

  • Too many observers cause performance issues

In large systems, you often use:

  • Message queues (Kafka, RabbitMQ)

  • Event buses

Which are distributed versions of Observer.


Interview Insight

If asked:

“What problem does Observer solve?”

Answer:

It removes tight coupling between the subject and dependent services by introducing a subscription mechanism.

If asked:

“What are its drawbacks?”

Answer:

  • Hard to debug cascading updates

  • Possible memory leaks if observers aren’t removed

  • Performance impact with many observers


Final Thoughts

Observer Pattern is about:

Designing systems that react to changes without tight coupling.

It’s essential for:

  • Scalable backend systems

  • Event-driven architecture

  • Clean service separation