Implementing Observer Pattern with References
How can I use references to implement a simple observer pattern in C++?
The Observer pattern is a software design pattern where an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes. We can implement this pattern in C++ using references for a clean and efficient design.
Here's a simple implementation:
#include <iostream>
#include <string>
#include <vector>
class Observer {
public:
virtual void Update(
const std::string& message) = 0;
virtual ~Observer() = default;
};
class Subject {
private:
std::vector<Observer*> observers;
std::string state;
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 SetState(const std::string& newState) {
state = newState;
Notify();
}
void Notify() {
for (auto observer : observers) {
observer->Update(state);
}
}
};
class ConcreteObserver : public Observer {
private:
std::string name;
public:
ConcreteObserver(const std::string& observerName)
: name{observerName} {}
void Update(const std::string& message) override {
std::cout << name << " received message: "
<< message << '\n';
}
};
int main() {
Subject subject;
ConcreteObserver observer1{"Observer 1"};
ConcreteObserver observer2{"Observer 2"};
subject.Attach(observer1);
subject.Attach(observer2);
subject.SetState("Hello, observers!");
subject.Detach(observer2);
subject.SetState("Observer 2 won't see this.");
}Observer 1 received message: Hello, observers!
Observer 2 received message: Hello, observers!
Observer 1 received message: Observer 2 won't see this.Let's break this down:
- We define an
Observerinterface with a pure virtualUpdate()method. - The
Subjectclass maintains a list of observer pointers. We use pointers here becausestd::vectorcan't store references directly. - The
Attach()andDetach()methods inSubjecttake references toObserverobjects. This provides a clean syntax for the user of the class and ensures that null observers can't be attached. - When
SetState()is called, it updates the state and callsNotify(), which updates all observers. ConcreteObserveris an implementation of theObserverinterface.- In
main(), we create a subject and two observers, attach the observers, set the subject's state (which notifies the observers), detach an observer, and set the state again.
Using references in the Attach() and Detach() methods provides several benefits:
- It's more intuitive: passing by reference clearly communicates that we're working with an existing object.
- It's safer: you can't pass a null reference, unlike with pointers.
- It's efficient: no need to check for null before dereferencing.
Remember, while we're using references in the interface, we're storing pointers internally. This is a common pattern when you need a mutable collection of references.
References
This lesson introduces references, explaining how they work, their benefits, and their role in performance and data manipulation