Observer Design Pattern in C++
The Observer design pattern is a behavioural design pattern that allows an object (known as the subject) to notify other objects (known as observers) when its state changes. This is useful in cases where you want to maintain consistency between related objects without making the objects tightly coupled.
Example
Here is an example of the Observer design pattern in C++:
#include <iostream>
#include <vector>
// Forward declaration of the Subject class
class Subject;
// The Observer class has a virtual update function that can be
// overridden by derived classes. It also has a constructor that
// takes a Subject as an argument and registers itself as an observer
// of that subject.
class Observer {
public:
Observer(Subject* subject) {
subject_ = subject;
subject_->Attach(this);
}
virtual ~Observer() {}
virtual void Update() = 0;
private:
Subject* subject_;
};
// The Subject class has a vector of observers and functions to add
// or remove observers from the vector. It also has a virtual function
// called Notify that can be overridden by derived classes.
class Subject {
public:
Subject() {}
virtual ~Subject() {}
void Attach(Observer* observer) {
observers_.push_back(observer);}
void Detach(Observer* observer) {
for (size_ti = 0; i<observers_.size(); ++i) {
if (observers_[i] == observer) {
observers_.erase(observers_.begin() + i);
break;} } }
virtual void Notify() {
for (auto observer : observers_) {
observer->Update();} }
private:
std::vector<Observer*> observers_;};
// A concrete subject class that stores a single integer value.
// It has a function called SetValue that updates the value and
// notifies observers when the value changes.
class IntSubject : public Subject {
public:
IntSubject() : value_(0) {}
int GetValue() const { return value_; }
void SetValue(int value) {
if (value_ != value) {
value_ = value;
Notify();}}
private:
int value_; };
// A concrete observer class that displays the value of an IntSubject
class IntObserver : public Observer {
public:
IntObserver(IntSubject* subject) : Observer(subject) {}
void Update() override {
std::cout<< "IntObserver: Subject value is now "
<<static_cast<IntSubject*>(subject_)->GetValue() << std::endl;
};
}
int main() {
IntSubject subject;
IntObserver observer1(&subject);
IntObserver observer2(&subject);
subject.SetValue(5);
subject.SetValue(10);
subject.SetValue(10); // No update should be triggered
return 0;
}
This example defines a Subject class with functions to attach and detach observers and a virtual Notify function that derived classes can override.
When to Use Observer Design?
It would be best if you used the Observer design pattern in C++ to establish a one-to-many relationship between objects, such that when one object (the subject) changes state, all the dependent objects (the observers) are notified and updated automatically.
This pattern is useful in cases where you want to maintain consistency between related objects without making the objects tightly coupled. For example, consider a graphical user interface (GUI) where multiple widgets (observers) display the same data and need to be updated whenever the data changes. Using the Observer pattern, you can design the widgets and the data as separate classes and have the widgets register themselves as observers of the data. When the data changes, it can notify all its registered observers, then update its display.
Another example where the Observer pattern can be useful is in a stock ticker application, where multiple clients (observers) are interested in receiving updates on the latest stock prices. The stock ticker (the subject) can notify all the registered clients (the observers) whenever the prices change.
In general, you should use the Observer pattern when:
- There is a one-to-many relationship between objects, such that when one objects changes state, all its dependents are notified and updated automatically.
- You want to abstract the details of the objects that depend on the subject from the subject itself.
- You want to change the dependencies between objects at runtime.You want to minimize the coupling between objects, such that the subject and its dependents are loosely coupled.
Advantages of Observer Design Pattern
The Observer design pattern has several advantages:
- It decouples the subject from its observers, which makes it easier to change the subject and the observers independently.
- It allows a subject to notifying its observers generically without the subject knowing the specifics of the observers.
- It allows a subject to have any number of observers, which can be added or removed at runtime.
- It allows observers to be notified of a subject's state changes as soon as they occur, rather than polling the subject for updates.
- It allows observers to be added or removed from a subject dynamically, at runtime, without modifying the subject's code.