Observer design pattern
Amit Nadiger
Polyglot(Rust??, C++ 11,14,17,20, C, Kotlin, Java) Android TV, Cas, Blockchain, Polkadot, UTXO, Substrate, Wasm, Proxy-wasm,AndroidTV, Dvb, STB, Linux, Engineering management.
The Observer pattern is a design pattern that facilitates communication between objects in a system. It is a behavioral pattern that allows an object, called the subject, to notify other objects, called observers, of any state changes it undergoes. In this article, we will explore the Observer pattern in more detail, including how it works, its advantages and limitations, and a sample code implementation.
How does the Observer pattern work?
The Observer pattern consists of two main components: the subject and the observers. The subject is the object that is being observed, while the observers are the objects that receive notifications when the subject's state changes. The subject maintains a list of its observers, and when its state changes, it notifies all the observers by calling a method on each observer.
In practice, the Observer pattern can be implemented using various programming constructs such as interfaces, abstract classes, and event listeners. In this example, we will use an interface to define the subject and observer objects.
?___________________? ? ? ? ? ? ______________________
|? ? ? ? ? ? ? ? ? ?|? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? |
|? ? Subject? ? ? ? |<>--------|? ? ?Observer? ? ? ? ?|
|___________________|? ? ? ? ? |______________________|
|? ? ? ? ? ? ? ? ? ?|? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? |
| + attach(observer)|? ? ? ? ? | + update()? ? ? ? ? ?|
| + detach(observer)|? ? ? ? ? |______________________|
| + notify()? ? ? ? |
|___________________|
Example Code
Let's consider a simple example of a weather station that provides weather information to its subscribers. The weather station is the subject, while the subscribers are the observers. The weather station periodically updates its weather information, and it needs to notify its subscribers of these updates.
C++ code:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// Observer interface
class WeatherObserver {
public:
? ? virtual void update(float temperature, float humidity, float pressure) = 0;
? ? virtual ~WeatherObserver() {}
};
// Subject interface
class WeatherStation {
public:
? ? virtual void subscribe(WeatherObserver* observer) = 0;
? ? virtual void unsubscribe(WeatherObserver* observer) = 0;
? ? virtual void notifyObservers() = 0;
virtual void updateWeather(float temperature, float humidity, float pressure) = 0;
? ? virtual ~WeatherStation() {}
};
// WeatherStation implementation
class WeatherStationImpl : public WeatherStation {
private:
? ? std::vector<WeatherObserver*> observers;
? ? float temperature;
? ? float humidity;
? ? float pressure;
public:
? ? void subscribe(WeatherObserver* observer) {
? ? ? ? observers.push_back(observer);
? ? }
? ? void unsubscribe(WeatherObserver* observer) {
? ? ? ? observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
? ? }
? ? void notifyObservers() {
? ? ? ? for (WeatherObserver* observer : observers) {
? ? ? ? ? ? observer->update(temperature, humidity, pressure);
? ? ? ? }
? ? }
? ? void updateWeather(float temperature, float humidity, float pressure) {
? ? ? ? this->temperature = temperature;
? ? ? ? this->humidity = humidity;
? ? ? ? this->pressure = pressure;
? ? ? ? notifyObservers();
? ? }
};
// Observer implementation
class WeatherSubscriber : public WeatherObserver {
private:
? ? std::string name;
public:
? ? WeatherSubscriber(std::string name) : name(name) {}
? ? void update(float temperature, float humidity, float pressure) {
? ? ? ? std::cout << name << ": temperature = " << temperature << ", humidity = " << humidity
? ? ? ? ? ? ? ? ? << ", pressure = " << pressure << std::endl;
? ? }
};
int main() {
? ? WeatherStation* weatherStation = new WeatherStationImpl();?
? ? WeatherObserver* subscriber11 = new WeatherSubscriber("Subscriber 11");
? ? WeatherObserver* subscriber12 = new WeatherSubscriber("Subscriber 12");
? ? weatherStation->subscribe(subscriber11);
? ? weatherStation->subscribe(subscriber12);
? ? weatherStation->updateWeather(25.5f, 70.2f, 1013.5f);
? ? weatherStation->unsubscribe(subscriber12);
? ? weatherStation->updateWeather(26.0f, 68.7f, 1015.5f);
? ? delete subscriber11;
? ? delete subscriber12;
? ? delete weatherStation;
? ? return 0;
}
/*
amit@DESKTOP-9LTOFUP:~/OmPracticeC++$ ./a.out
Subscriber 11: temperature = 25.5, humidity = 70.2, pressure = 1013.5
Subscriber 12: temperature = 25.5, humidity = 70.2, pressure = 1013.5
Subscriber 11: temperature = 26, humidity = 68.7, pressure = 1015.5
*/
Kotlin Code:
// Subject interface
interface WeatherStation {
? ? fun subscribe(observer: WeatherObserver)
? ? fun unsubscribe(observer: WeatherObserver)
? ? fun notifyObservers()
}
// Observer interface
interface WeatherObserver {
? ? fun update(temperature: Float, humidity: Float, pressure: Float)
}
// WeatherStation implementation
class WeatherStationImpl : WeatherStation {
? ? private val observers: MutableList<WeatherObserver> = mutableListOf()
? ? private var temperature: Float = 0.0f
? ? private var humidity: Float = 0.0f
? ? private var pressure: Float = 0.0f
? ? override fun subscribe(observer: WeatherObserver) {
? ? ? ? observers.add(observer)
? ? }
? ? override fun unsubscribe(observer: WeatherObserver) {
? ? ? ? observers.remove(observer)
? ? }
? ? override fun notifyObservers() {
? ? ? ? observers.forEach { it.update(temperature, humidity, pressure) }
? ? }
? ? fun updateWeather(temperature: Float, humidity: Float, pressure: Float) {
? ? ? ? this.temperature = temperature
? ? ? ? this.humidity = humidity
? ? ? ? this.pressure = pressure
? ? ? ? notifyObservers()
? ? }
}
// Observer implementation
class WeatherSubscriber(private val name: String) : WeatherObserver {
? ? override fun update(temperature: Float, humidity: Float, pressure: Float) {
? ? ? ? println("$name: temperature = $temperature, humidity = $humidity, pressure = $pressure")
? ? }
}
In the above code, we define two interfaces: WeatherStation and WeatherObserver. The WeatherStation interface defines the methods that the subject object must implement, while the WeatherObserver interface defines the methods that the observer objects must implement.
领英推荐
We then define two classes: WeatherStationImpl and WeatherSubscriber. The WeatherStationImpl class implements the WeatherStation interface, and it maintains a list of observers. It also has a method to update the weather information, which it does by changing the temperature, humidity, and pressure fields, and then calling the notifyObservers() method.
The WeatherSubscriber class implements the WeatherObserver interface. It has a method called update() that is called when the subject notifies it of a state change. In this case, the update() method simply prints the weather information to the console.
Advantages of the Observer pattern
Limitations of Observer pattern:
Some of the application of observer pattern :
The Observer pattern is widely used in various software applications where the state of an object needs to be monitored and notified to a set of interested clients in real-time. Here are some examples of applications of the Observer pattern:
These are just a few examples of applications of the Observer pattern. In general, the Observer pattern is used in any system where the state of an object needs to be monitored by multiple clients in real-time.
The Observer Pattern is a powerful and flexible pattern that has many applications in software development. It is commonly used in event-driven systems, user interfaces, and real-time systems where there is a need to track changes in data or events.
Thanks for reading till end , please comment if you have any suggestions.