C++ Observer Pattern Example

1. Definition

The Observer Design Pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. It is mainly used for implementing distributed event handling systems.

2. Problem Statement

In many situations, a set of objects needs to be updated when another object changes. Doing this without an organized pattern can make the code complex, less maintainable, and may cause inadvertent errors.

3. Solution

The Observer pattern involves mainly two types of participants:

1. **Subject**: Maintains a list of observers and provides methods to add, remove, and notify them.

2. **Observer**: Provides an update interface for objects that should be notified of changes in the subject.

Whenever the subject undergoes a change, it notifies all its observers about the change.

4. Real-World Use Cases

1. News publishers and subscribers.

2. Model-View-Controller (MVC) where model is the subject and views are observers.

3. Monitoring systems.

4. Event management systems.

5. Implementation Steps

1. Define the Observer interface which includes an 'update' method.

2. Define the Subject interface with methods to attach, detach, and notify observers.

3. Implement concrete classes for both Observer and Subject interfaces.

6. Implementation in C++

// Observer Interface
class Observer {
public:
    virtual void update(int value) = 0;
};
// Subject Interface
class Subject {
    std::vector<Observer*> observers;
public:
    void attach(Observer* observer) {
        observers.push_back(observer);
    }
    void detach(Observer* observer) {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }
    void notify(int value) {
        for (Observer* observer : observers) {
            observer->update(value);
        }
    }
};
// Concrete Observer
class ConcreteObserver : public Observer {
    int observerState;
public:
    void update(int value) override {
        observerState = value;
        std::cout << "Observer updated with value: " << observerState << std::endl;
    }
};
// Example Usage
int main() {
    Subject subject;
    ConcreteObserver observer1, observer2;
    subject.attach(&observer1);
    subject.attach(&observer2);
    subject.notify(5); // Notify all observers with value 5
    subject.notify(10); // Notify all observers with value 10
    return 0;
}

Output:

Observer updated with value: 5
Observer updated with value: 5
Observer updated with value: 10
Observer updated with value: 10

Explanation:

1. The Observer interface provides an 'update' method which is called to notify the observer of changes.

2. The Subject maintains a list of observers and can add, remove, or notify observers.

3. In the example, two observers (observer1 and observer2) are attached to the subject. When the subject notifies its observers with values 5 and 10, both observers print the updated value.

7. When to use?

Use the Observer pattern when:

1. An abstraction has two aspects, one dependent on the other. Encapsulating these aspects in separate objects lets you vary and reuse them independently.

2. A change to one object requires changing others, but you don't know how many objects need to be changed.

3. An object should notify other objects without making assumptions about who these objects are.


Comments