CLOSE
Updated on 19 Aug, 202516 mins read 122 views

Definition

The Observer Design Pattern is a behavioral design pattern that defines a one-to-many relationship between objects. When one object (the subject) changes its state, all its dependents (the observers) are notified and updated automatically.

It promotes loose coupling:

  • The Subject doesn't need to know the concrete classes of its Observers.
  • Observers can be added/removed at runtime dynamically.

Intent

  • Decouple the subject and its observers, allowing them to vary independently.
  • Ensure that changes in the subject are reflected in the observers without direct coupling.

Key Components

  1. Subject: Maintains a list of observers and notifies them of any state changes.
    1. Maintains a list of observers.
    2. Provides methods to attach/detach observers.
    3. Notifies all observers when its state changes.
  2. Observer Interface: Defines the method(s) used by the subject to notify observers.
    1. Abstract interface with an update() method.
    2. Concrete Observers implement this method.
  3. Concrete Subject:
    1. Holds state of interest.
    2. When state changers, it calls notify().
  4. Concrete Observer: Implements the observer interface and updates itself in response to changes in the subject.

When to Use

  • When changes to one object need to automatically trigger updates in dependent objects.
  • To implement event-driven programming or publish/subscribe mechanisms.

Example

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

class ISubscriber {
public:
    virtual void update() = 0;
    virtual ~ISubscriber() {}  // virtual destructor for interface
};
    
// Abstract Observable interface: a YouTube channel interface
class IChannel {
public:
    virtual void subscribe(ISubscriber* subscriber) = 0;
    virtual void unsubscribe(ISubscriber* subscriber) = 0;
    virtual void notifySubscribers() = 0;
    virtual ~IChannel() {}
};

// Concrete Subject: a YouTube channel that observers can subscribe to
class Channel : public IChannel {
private:
    vector<ISubscriber*> subscribers;  // list of subscribers
    string name;
    string latestVideo;               // latest uploaded video title
public:
    Channel(const string& name) {
        this->name = name;
    }

    // Add a subscriber (avoid duplicates)
    void subscribe(ISubscriber* subscriber) override {
        if (find(subscribers.begin(), subscribers.end(), subscriber) == subscribers.end()) {
            subscribers.push_back(subscriber);
        }
    }

    // Remove a subscriber if present
    void unsubscribe(ISubscriber* subscriber) override {
        auto it = find(subscribers.begin(), subscribers.end(), subscriber);
        if (it != subscribers.end()) {
            subscribers.erase(it);
        }
    }

    // Notify all subscribers of the latest video
    void notifySubscribers() override {
        for (ISubscriber* sub : subscribers) {
            sub->update();
        }
    }

    // Upload a new video and notify all subscribers
    void uploadVideo(const string& title) {
        latestVideo = title;
        cout << "\n[" << name << " uploaded \"" << title << "\"]\n";
        notifySubscribers();
    }

    // Read video data
    string getVideoData() {
        return "\nCheckout our new Video : " + latestVideo + "\n";
    }
};

// Concrete Observer: represents a subscriber to the channel
class Subscriber : public ISubscriber {
private:
    string name;
    Channel* channel;
public:
    Subscriber(const string& name, Channel* channel) {
        this->name = name;
        this->channel = channel;
    }

    // Called by Channel; prints notification message
    void update() override {
        cout << "Hey " << name << "," << this->channel->getVideoData();
    }
};

int main() {
    // Create a channel and subscribers
    Channel* channel = new Channel("TheJat");

    Subscriber* subs1 = new Subscriber("Ikka", channel);
    Subscriber* subs2 = new Subscriber("Dukka", channel);

    // Ikka and Dukka subscribe to TheJat
    channel->subscribe(subs1);
    channel->subscribe(subs2);

    // Upload a video: both Ikka and Dukka are notified
    channel->uploadVideo("Observer Pattern Tutorial");

    // Ikka unsubscribes; Dukka remains subscribed
    channel->unsubscribe(subs1);

    // Upload another video: only Dukka is notified
    channel->uploadVideo("Decorator Pattern Tutorial");

    return 0;
}

Output:


[TheJat uploaded "Observer Pattern Tutorial"]
Hey Ikka,
Checkout our new Video : Observer Pattern Tutorial
Hey Dukka,
Checkout our new Video : Observer Pattern Tutorial

[TheJat uploaded "Decorator Pattern Tutorial"]
Hey Dukka,
Checkout our new Video : Decorator Pattern Tutorial
 
Normal program termination. Exit status: 0

 

Leave a comment

Your email address will not be published. Required fields are marked *