Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding the Observer Design Pattern in C++

Tech 1

The Observer pattern is a behavioral design pattern that establishes a one-to-many dependency relationship between objects. When the state of one object changes, all dependent objects are automatically notified and updated. This pattern is particularly useful in scenarios where multiple objects need to react to events occurring in another object, or when there's a need for reverse notification from member objects back to the main object.

Consider a scenario where employees are monitoring stock prices and entertainment content during work hours. When the manager returns to the office, a receptionist alertts all employees, who then immediately switch their screens back to work-related content. This real-world situation perfectly illustrates the Observer pattern in action.

Observer Interface

The observer defines a contract for objects that need to be notified of state changes:

class IEventListener
{
public:
    virtual ~IEventListener() {}
    
    virtual void handleEvent(const std::string& eventData) = 0;
};

Concrete Observer Implementation

Each concrete observer implements the notification interface and defines its own response behavior:

class ConcreteListener : public IEventListener
{
public:
    ConcreteListener(const std::string& name) : m_name(name) {}
    virtual ~ConcreteListener() {}
    
    virtual void handleEvent(const std::string& eventData) override
    {
        std::cout << m_name << " received event: " << eventData << std::endl;
    }

private:
    std::string m_name;
};

Subject Base Class

The subject maintains a list of observers and provides methods to attach, detach, and notify them:

class Subject
{
public:
    Subject() {}
    virtual ~Subject() {}

    bool attach(IEventListener* pListener)
    {
        if (pListener)
        {
            m_listeners.push_back(pListener);
            return true;
        }
        return false;
    }

    void detach(IEventListener* pListener)
    {
        m_listeners.remove(pListener);
    }

    void notifyAll(const std::string& eventData)
    {
        if (!m_listeners.empty())
        {
            for (auto it = m_listeners.begin(); it != m_listeners.end(); ++it)
            {
                IEventListener* pListener = *it;
                pListener->handleEvent(eventData);
            }
        }
    }

private:
    std::list<IEventListener*> m_listeners;
};

Concrete Subject

The concrete subject inherits from the base class and triggers notifications when specific events occur:

class Manager : public Subject
{
public:
    void arrive()
    {
        std::cout << "Manager: I have arrived at the office" << std::endl;
        notifyAll("Manager Arrived");
    }

    void depart()
    {
        std::cout << "Manager: Leaving the office now" << std::endl;
        notifyAll("Manager Left");
    }
};

Usage Example

void ObserverPatternDemo()
{
    ConcreteListener listener1("Alice");
    ConcreteListener listener2("Bob");
    Manager officeManager;
    
    officeManager.attach(&listener1);
    officeManager.attach(&listener2);
    
    officeManager.arrive();
    
    // Remove listener1 after manager arrives
    officeManager.detach(&listener1);
    
    officeManager.depart();
}

Output:

Manager: I have arrived at the office
Alice received event: Manager Arrived
Bob received event: Manager Arrived
Manager: Leaving the office now
Bob received event: Manager Left

This pattern is widely used in various applications. For instance, when using messaging applications across multiple devices, incoming messages trigger notifications on all connected clients simultaneously. Each device acts as an observer, and the message server serves as the subject that broadcasts notifications to all subscribers.

Tags: C++

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.