DEV Community

Cover image for Design Patterns Simplified: Part 3 – Observer Pattern (a.k.a. “Don’t Call Me, I’ll Call You 📞”)
Prateek Prabhakar
Prateek Prabhakar

Posted on • Edited on • Originally published at Medium

Design Patterns Simplified: Part 3 – Observer Pattern (a.k.a. “Don’t Call Me, I’ll Call You 📞”)

Observer Pattern belongs to the Behavioral category of design patterns.

Why? Because it's all about how different objects interact, especially when one changes and others need to react. It can be called a notification pattern - “Hey, something changed. Do your thing now.”


YouTube Channel Subscriptions

Let’s say you just started a YouTube channel. You have 100 subscribers.
Every time you upload a new video, all subscribers should get notified (and that is what you want, to have the most number of followers on the planet 😎)

So you could do something like,

Function UploadVideo(video)
    Notify(user1)
    Notify(user2)
    ...
    Notify(user100)
    ...
    ...
    Notify(user1000)
Enter fullscreen mode Exit fullscreen mode

But wait! Is this really scalable?
What if,

  • 1 more user subscribes?
  • 10 users unsubscribe?
  • You plan to add a notification via email, push or discord in future.

I am confident enough that you would agree that this soon becomes a mess to manage.


Enter the Observer Pattern

The basic principle of this pattern would be to, allow other objects “subscribe” to changes and automatically get notified when something important happens.

What does the code look like?

// Step 1: Observer Interface
Interface Subscriber
    Method Notify(video)

// Step 2: User class (Observer)
Class User Implements Subscriber
    Constructor(name)
        this.name = name

    Method Notify(video)
        Print("New video " + video.title + " has been uploaded")

// Step 3: YouTube Channel (Subject)
Class YouTubeChannel
    List<Subscriber> subscribers = []

    Method Subscribe(subscriber)
        subscribers.Add(subscriber)

    Method Unsubscribe(subscriber)
        subscribers.Remove(subscriber)

    Method UploadVideo(video)
        Print("Uploading: " + video.title)
        ForEach(sub in subscribers)
            sub.Notify(video)

//Caller logic
channel = new YouTubeChannel()
alice = new User("Alice")
bob = new User("Bob")

channel.Subscribe(alice)
channel.Subscribe(bob)

video = new Video("Observer Pattern Simplified")
channel.UploadVideo(video)

Enter fullscreen mode Exit fullscreen mode

How does this code handle all those pain points we talked about earlier?

Q: What if one more user subscribes?
A: Just call channel.Subscribe(new User("Charlie"))
No change needed in UploadVideo() or other logic because the observer pattern handles this dynamically.

Q: What if 10 users unsubscribe?
A: Loop through the set of users and call channel.Unsubscribe(user)
Again, no change to your UploadVideo() method. Subscribers manage themselves, and your main logic stays clean.

Q: What if you want to notify via different(newer) channels?
A: You can extend User to include preferences (Email, Push, Discord) and then customize the Notify() method per user.
Something like,

Class User Implements Subscriber
    Constructor(name, preferences)
        this.name = name
        this.preferences = preferences  // e.g. ["Email", "Push"]

    Method Notify(video)
        If "Email" in preferences
            SendEmail(this.name, video)
        If "Push" in preferences
            SendPush(this.name, video)
        If "Discord" in preferences
            SendDiscordMessage(this.name, video)
Enter fullscreen mode Exit fullscreen mode

Alternatively, you could use the Decorator or Composite Pattern to wrap multiple notification types, which we'll explore in upcoming posts. Stay tuned!

Why Use Observer Pattern?

  • To notify multiple systems/objects when one thing changes
  • Want dynamic subscribers i.e. objects that can come and go
  • Want to follow Open-Closed Principle (no modifying your main logic to add new notification channels)

Use Cases?

  • UI Event Listeners (button clicks, value changes)
  • Notification systems (Email, SMS, Push)
  • Stock/Price change alerts
  • Chat applications (new message broadcast)
  • Realtime dashboards (when backend data updates)

To summarize, it would be apt to say,

The Observer Pattern lets you define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified automatically.

It is like a publisher-subscriber system inside your code that is simple, powerful, and perfect for decoupling.

If you found this helpful, follow the series or share it with someone preparing for system design or tech interviews.

Next up in the series: Decorator Pattern. Dive right in!

Top comments (0)