👀 Observer Design Pattern in Java

👀 Observer Design Pattern in Java

In dynamic applications where changes in one object need to be automatically reflected across others, the Observer Design Pattern is the go-to solution.

It enables a one-to-many dependency between objects so when one object (the Subject) changes state, all its dependents (the Observers) are notified automatically.


🌍 Real-World Analogies for the Observer Pattern

1. YouTube Channel & Subscribers

  • Subject: YouTube Channel
  • Observers: Subscribers
  • Trigger: When a creator uploads a new video, YouTube notifies all subscribers.
  • If a user unsubscribes, they stop getting updates. This is a perfect analogy for the observer pattern—where multiple observers depend on a single subject's change.


2. Newsletter Subscription

  • Subject: News Publisher (e.g., New York Times)
  • Observers: Email subscribers
  • Every time the publisher sends out a newsletter, all subscribed users receive it.
  • If you unsubscribe, you’re no longer notified. ✅ Just like addObserver() and removeObserver() methods in code.

// Subscriber.java

// A subscriber can subscribe the youtube channel in multiple way like through email,sms, youtube push notification 


package LLD.ObserverDesign;

interface Subscriber{
    void getnotify();
    String getName();
}

class BellIcon implements Subscriber{
    private String name;
    BellIcon(String name){
        this.name=name;
    }
    public void getnotify() {
        System.out.println(name+ " subscriber is notified through bell icon");
    }
    public String getName(){
        return this.name;
    }
}

class Email implements Subscriber{
    private String name;
    Email(String name){
        this.name=name;
    }
    public void getnotify() {
        System.out.println(name+" subscriber is notified through Email");
    }
    public String getName(){
        return this.name;
    }
}

class Sms implements Subscriber{
    private String name;
    Sms(String name){
        this.name=name;
    }
    public String getName(){
        return this.name;
    }
    public void getnotify() {
        System.out.println(name+" subscriber is notified through Sms");
    }
}

        
// YoutubeChannel.java 

// Here we declare the youtubechannel interface and its concreate implementation.

package LLD.ObserverDesign;
import java.util.*;

interface YouTubeChannel {
    // Method to add a new subscriber
    void addSubscriber(Subscriber subscriber); 
    // Method to remove a subscriber
    void removeSubscriber(Subscriber subscriber); 
    void notifySubscribers(); // Method to notify all subscribers
    void addcontent();
}
class YoutubeChannelclass implements YouTubeChannel {
    private String channelName;
    private List<Subscriber> allsubs = new ArrayList<Subscriber>();
    YoutubeChannelclass(String name) {
        this.channelName = name;
        System.out.println("Creating a youtube channel of name: " + channelName);
    }
    public void addSubscriber(Subscriber sub) {
        System.out.println("Adding subscriber: " + sub.getName() + " to channel " + channelName);
        allsubs.add(sub);
    }
  public void removeSubscriber(Subscriber sub) {
 System.out.println("Removing subscriber:"+sub.getName()+" "+channelName);
        allsubs.remove(sub);
    }

   // Notify All Subs
    public void notifySubscribers() {
        System.out.println("Notify all subscriber of: " + channelName);
        for (Subscriber sub : allsubs) {
            sub.getnotify();
        }
    }

   public void addcontent() {
       System.out.println("Adding a new video to youtube: "+channelName);
        notifySubscribers(); // notify the subs abt new video
    }
}        
// Clien code Main.java

package LLD.ObserverDesign;

public class Main{
    public static void main(String[] args){
        System.out.println("Hello World from Main.java");
        // lets create some youtube channel
        YoutubeChannelclass travel=new YoutubeChannelclass("travel");
        YoutubeChannelclass foodBlog=new YoutubeChannelclass("foodBlog");

        // create few subscriber 
        Sms obs1=new Sms("obs1");
        BellIcon obs2=new BellIcon("obs2");
        Email obs3=new Email("obs3");
        BellIcon obs4=new BellIcon("obs4");


        // add the subs to channel

        travel.addSubscriber(obs1);
        travel.addSubscriber(obs4);
        foodBlog.addSubscriber(obs3);
        foodBlog.addSubscriber(obs2);

        // add content on channel
        travel.addcontent();
        System.out.println("");
        foodBlog.addcontent();

    }
}        

✅ When to Use Observer Pattern

  • GUI frameworks: Button click listeners
  • Messaging systems: Subscribers for topics
  • Event-driven systems: Webhooks, notification services
  • Monitoring: Logging or audit services


🚫 When Not to Use It?

  • When tight coupling is a concern
  • When observer count is huge (can cause performance overhead)
  • If notifications must be synchronous but can cause delays or failures


📌 Final Thoughts

The Observer pattern helps you build reactive and decoupled systems. It's particularly powerful in event-driven architectures, especially when implemented with thread safety in mind.

It promotes scalability, flexibility, and better separation of concerns.


🔁 Have you used the Observer pattern in a real-world project? 👇 Share your use cases or challenges in the comments.

#Java #DesignPatterns #ObserverPattern #EventDriven #Multithreading #SoftwareEngineering #CodingTips #JavaDeveloper #SystemDesign #CleanArchitecture

To view or add a comment, sign in

More articles by Samartha Khare

Explore content categories