The Observer is a useful pattern to decouple producers and consumers by registering consumers with a producer. On specific events, the producer will call the API to send data to each consumer (observer). It’s similar to app notifications.
Link to UVM Link to heading
TLM ports and exports depend heavily on the Observer pattern. Whenever connect
is called, the export is added to the list of observers for ports. When a new object is generated, the ports call back all the observers.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
// Observer interface
class Observer {
public:
virtual void update(const std::string& message) = 0;
virtual ~Observer() = default;
};
// Subject interface
class Subject {
private:
std::vector<Observer*> observers;
public:
void addObserver(Observer* observer) {
observers.push_back(observer);
}
void removeObserver(Observer* observer) {
observers.erase(
std::remove(observers.begin(), observers.end(), observer),
observers.end()
);
}
void notifyObservers(const std::string& message) {
for (auto observer : observers) {
observer->update(message);
}
}
};
// Concrete Subject - Weather Station
class WeatherStation : public Subject {
private:
float temperature;
float humidity;
public:
void setWeatherData(float temp, float hum) {
temperature = temp;
humidity = hum;
std::string weatherUpdate = "Temperature: " + std::to_string(temperature) +
"°C, Humidity: " + std::to_string(humidity) + "%";
notifyObservers(weatherUpdate);
}
float getTemperature() const { return temperature; }
float getHumidity() const { return humidity; }
};
// Concrete Observer - Mobile App
class MobileApp : public Observer {
private:
std::string appName;
public:
MobileApp(const std::string& name) : appName(name) {}
void update(const std::string& message) override {
std::cout << "[" << appName << " App] Weather Update: " << message << std::endl;
}
};
// Concrete Observer - Display Board
class DisplayBoard : public Observer {
private:
std::string location;
public:
DisplayBoard(const std::string& loc) : location(loc) {}
void update(const std::string& message) override {
std::cout << "[Display at " << location << "] " << message << std::endl;
}
};
// Concrete Observer - Alert System
class AlertSystem : public Observer {
private:
float alertThreshold;
public:
AlertSystem(float threshold) : alertThreshold(threshold) {}
void update(const std::string& message) override {
std::cout << "[Alert System] " << message;
// Simple alert logic (parse temperature from message)
size_t pos = message.find("Temperature: ");
if (pos != std::string::npos) {
float temp = std::stof(message.substr(pos + 13));
if (temp > alertThreshold) {
std::cout << " ⚠️ HIGH TEMPERATURE ALERT!";
}
}
std::cout << std::endl;
}
};
int main() {
std::cout << "=== Observer Pattern Demo ===" << std::endl;
// Create weather station (subject)
WeatherStation weatherStation;
// Create observers
MobileApp mobileApp("WeatherPro");
DisplayBoard displayBoard("City Center");
AlertSystem alertSystem(30.0f); // Alert if temp > 30°C
// Register observers
weatherStation.addObserver(&mobileApp);
weatherStation.addObserver(&displayBoard);
weatherStation.addObserver(&alertSystem);
std::cout << "\n1. Initial weather update:" << std::endl;
weatherStation.setWeatherData(25.5f, 60.0f);
std::cout << "\n2. Hot weather update:" << std::endl;
weatherStation.setWeatherData(35.0f, 45.0f);
std::cout << "\n3. Removing mobile app observer:" << std::endl;
weatherStation.removeObserver(&mobileApp);
std::cout << "\n4. Weather update after removal:" << std::endl;
weatherStation.setWeatherData(28.0f, 70.0f);
return 0;
}