When developing software, it is often necessary to implement a communication pattern where one or more objects are notified when a particular event occurs in another object. The Observer pattern provides a solution to this problem by allowing objects (observers) to subscribe to events in a subject object and receive notifications when those events occur.
In C++, we can implement the Observer pattern using functors, which are objects that can be called like functions. Functors provide a flexible way to encapsulate the observer logic and allow for customization behavior.
The Subject Class
Let’s start by implementing the subject class, which is the object that generates events and notifies the observers.
class Subject {
public:
using ObserverFn = std::function<void()>;
void subscribe(const ObserverFn& observer) {
observers.push_back(observer);
}
void notify() {
for (const auto& observer : observers) {
observer();
}
}
private:
std::vector<ObserverFn> observers;
};
In the code above, we define a Subject
class that contains a vector of ObserverFn
, which is the type alias for our functor-based observer. The subscribe
function allows observers to subscribe to events, and the notify
function iterates over all observers and calls them.
The Observer Class
Now, let’s create an example of an observer class that will handle the events generated by the subject.
class Observer {
public:
explicit Observer(const std::string& name) : name_(name) {}
void operator()() const {
std::cout << "Observer " << name_ << " received notification\n";
}
private:
std::string name_;
};
In this example, we define an Observer
class with a constructor that takes a name as a parameter. The operator()
function is implemented, which allows the object to be called like a function. When the observer is called, it simply prints a notification message.
Putting it all together
Now, let’s put everything together and see how we can use the observer pattern implemented with functors.
int main() {
Subject subject;
Observer observer1("Observer 1");
Observer observer2("Observer 2");
subject.subscribe(observer1);
subject.subscribe(observer2);
std::cout << "Notifying observers...\n";
subject.notify();
return 0;
}
In the main function, we create a Subject
object and two Observer
objects. We subscribe both observers to the subject
using the subscribe
function. Finally, we call subject.notify()
to trigger the notification process.
When we run the above code, it will output:
Notifying observers...
Observer Observer 1 received notification
Observer Observer 2 received notification
As you can see, both observers receive the notification from the subject.
Conclusion
By implementing the functor-based observer pattern in C++, we can easily decouple the subject and observer objects, allowing for a flexible and customizable event notification mechanism. Functors provide a powerful and expressive way to define the observer logic, making our code more modular and maintainable.
So, next time you need to implement an observer pattern in C++, consider using functors for a clean and efficient solution.
#C++ #ObserverPattern #Functors