The Observer Pattern
This post is a cross-post from www.ModernesCpp.com.
The Observer Pattern is a behavioral pattern from the book?"Design Patterns: Elements of Reusable Object-Oriented Software". It defines 1-to-n dependencies between objects so that changes to one object cause all dependent objects to be notified.
The Observer Pattern solves a classical design issue: How can you ensure that all prospects are automatically notified if an important event has taken place?
The Observer Pattern
Purpose
Also known as
Use Case
Structure
?Subject
Observer
ConcreteObserver
I'm happy and proud to announce that my mentoring program, "Fundamentals for C++ Professionals", reopened in October, and my "Design Patterns and Architectural Patterns with C++"?starts in February 2023.
If you want to stay informed about my existing and upcoming mentoring programs, use the following link for registration: https://eepurl.com/idBPr9
Example
The following program observer.cpp directly implements the previous class diagram.
// observer.cpp
#include <iostream>
#include <list>
#include <string>
class Observer {
public:
virtual ~Observer(){};
virtual void notify() const = 0;
};
class Subject {
public:
void registerObserver(Observer* observer) {
observers.push_back(observer);
}
void unregisterObserver(Observer* observer) {
observers.remove(observer);
}
void notifyObservers() const { // (2)
for (auto observer: observers) observer->notify();
}
private:
std::list<Observer *> observers;
};
class ConcreteObserverA : public Observer {
public:
ConcreteObserverA(Subject& subject) : subject_(subject) {
subject_.registerObserver(this);
}
void notify() const override {
std::cout << "ConcreteObserverA::notify\n";
}
private:
Subject& subject_; // (3)
};
class ConcreteObserverB : public Observer {
public:
ConcreteObserverB(Subject& subject) : subject_(subject) {
subject_.registerObserver(this);
}
void notify() const override {
std::cout << "ConcreteObserverB::notify\n";
}
private:
Subject& subject_; // (4)
};
int main() {
std::cout << '\n';
Subject subject;
ConcreteObserverA observerA(subject);
ConcreteObserverB observerB(subject);
subject.notifyObservers();
std::cout << " subject.unregisterObserver(observerA)\n";
subject.unregisterObserver(&observerA); // (1)
subject.notifyObservers();
std::cout << '\n';
}
The Observer supports the member function notify, and the Subject supports the member functions registerObserver, unregisterObserver, and notifyObservers. The concrete observers receive the subject in their constructor and use them to register themself for the notification. They have a reference to the subject (lines 3 and 4).?Only observerA is unregistered in line (1). The member function notifyObservers goes through all registered observers and notifies them (line 2).
The following screenshot shows the output of the program:
By the way, you may have noticed that I used no memory allocation in the previous program observer.cpp. This is how virtuality is typically used if you aren't allowed to allocate memory, such as in deeply embedded systems. Here is the corresponding main function using memory allocation:
int main() {
std::cout << '\n';
Subject* subject = new Subject;
Observer* observerA = new ConcreteObserverA(*subject);
Observer* observerB = new ConcreteObserverB(*subject);
subject->notifyObservers();
std::cout << " subject->unregisterObserver(observerA)" << "\n";
subject->unregisterObserver(observerA);
subject->notifyObservers();
delete observerA;
delete observerB;
delete subject;
std::cout << '\n';
}
Know Uses
The Observer Patten is often used in architectural patterns such as Model-View-Controller (MVC)?for graphical user interfaces or Reactor for event handling.
领英推荐
I will dedicate an entire future post to both architectural patterns.
Variations
The Subject in the program observer.cpp simply sends a notification. However, more advanced workflows are often implemented:
The Subject sends a
Related Patterns
Pros and Cons
Pros
Cons
class ConcreteObserverA : public Observer {
public:
ConcreteObserverA(Subject& subject) : subject_(subject) {
subject_.registerObserver(this);
}
~ConcreteObserverA() noexcept {
subject_.unregisterObserver(this);
}
void notify() const override {
std::cout << "ConcreteObserverA::notify\n";
}
private:
Subject& subject_;
};
The concrete observer ConcreteObserverA models the RAII Idiom: It registers itself in its constructor and unregisters itself in its destructor.
What's next?
The Visitor Pattern has an ambivalent reputation. On one hand, enables the Visitor Double Dispatch. On the other hand, the Visitor is pretty complicated to implement. Let me introduce the Visitor Pattern in my next post.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, Marko, G Prvulovic, Reinhold Dr?ge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Louis St-Amour, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Neil Wang, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschl?ger, Alessandro Pezzato, Evangelos Denaxas, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, and Wolfgang Fütterer.
?
Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, Ralf Abramowitsch, John Nebel, Mipko, Alicja Kaminska, and Matthias Grün.
My special thanks to Embarcadero
My special thanks to PVS-Studio
?
Seminars
I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
Bookable (Online)
German
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
New
Contact Me