#include <iostream>
#include <vector>
#include <algorithm>

// Forward declaration
class Observer;
class Subject;

// ========== Observer Interface ==========
class Observer {
public:
    virtual ~Observer() = default;
    // Called when the subject state changes, passing temperature, humidity, and pressure
    virtual void update(float temperature, float humidity, float pressure) = 0;
};

// ========== Subject Interface ==========
class Subject {
public:
    virtual ~Subject() = default;
    virtual void registerObserver(Observer* o) = 0;
    virtual void removeObserver(Observer* o) = 0;
    virtual void notifyObservers() = 0;
};

// ========== Concrete Subject: Weather Station Data ==========
class WeatherData : public Subject {
private:
    std::vector<Observer*> observers;
    float temperature = 0.0f;
    float humidity = 0.0f;
    float pressure = 0.0f;

public:
    void registerObserver(Observer* o) override {
        observers.push_back(o);
        std::cout << "[WeatherData] Registered an observer\n";
    }

    void removeObserver(Observer* o) override {
        auto it = std::find(observers.begin(), observers.end(), o);
        if (it != observers.end()) {
            observers.erase(it);
            std::cout << "[WeatherData] Removed an observer\n";
        }
    }

    void notifyObservers() override {
        for (auto* observer : observers) {
            observer->update(temperature, humidity, pressure);
        }
    }

    // Called when new data is obtained from physical sensors
    void setMeasurements(float temp, float hum, float press) {
        std::cout << "\n--- Weather station update: temp=" << temp
                  << "°C, humidity=" << hum << "%, pressure=" << press << "hPa ---\n";
        temperature = temp;
        humidity = hum;
        pressure = press;
        notifyObservers();  // Notify all observers
    }
};

// ========== Concrete Observer: Current Conditions Display ==========
class CurrentConditionsDisplay : public Observer {
private:
    float temperature = 0.0f;
    float humidity = 0.0f;

public:
    void update(float temp, float hum, float /*pressure*/) override {
        temperature = temp;
        humidity = hum;
        display();
    }

    void display() const {
        std::cout << "[Current Conditions] Temperature: " << temperature
                  << "°C, humidity: " << humidity << "%\n";
    }
};

// ========== Concrete Observer: Statistics Display (Average/Max/Min Temperature) ==========
class StatisticsDisplay : public Observer {
private:
    float maxTemp = -100.0f;
    float minTemp = 200.0f;
    float sumTemp = 0.0f;
    int count = 0;

public:
    void update(float temp, float /*hum*/, float /*pressure*/) override {
        sumTemp += temp;
        count++;

        if (temp > maxTemp) maxTemp = temp;
        if (temp < minTemp) minTemp = temp;

        display();
    }

    void display() const {
        std::cout << "[Statistics] Average temperature: " << (sumTemp / count)
                  << "°C, max: " << maxTemp
                  << "°C, min: " << minTemp << "°C\n";
    }
};

// ========== Concrete Observer: Simple Forecast ==========
class ForecastDisplay : public Observer {
private:
    float lastPressure = 0.0f;
    float currentPressure = 0.0f;

public:
    void update(float /*temp*/, float /*hum*/, float pressure) override {
        lastPressure = currentPressure;
        currentPressure = pressure;
        display();
    }

    void display() const {
        std::cout << "[Forecast] ";
        if (currentPressure > lastPressure) {
            std::cout << "The weather is improving!\n";
        } else if (currentPressure < lastPressure) {
            std::cout << "The weather may get colder, bring an umbrella!\n";
        } else {
            std::cout << "The weather remains basically unchanged.\n";
        }
    }
};

// ========== Main Program ==========
int main() {
    // Create subject
    WeatherData weatherData;

    // Create observers
    CurrentConditionsDisplay currentDisplay;
    StatisticsDisplay statsDisplay;
    ForecastDisplay forecastDisplay;

    // Register observers
    weatherData.registerObserver(&currentDisplay);
    weatherData.registerObserver(&statsDisplay);
    weatherData.registerObserver(&forecastDisplay);

    // Simulate three weather updates
    weatherData.setMeasurements(25.0f, 65.0f, 1013.0f);
    weatherData.setMeasurements(27.5f, 70.0f, 1012.5f);
    weatherData.setMeasurements(26.0f, 68.0f, 1012.0f);

    // Remove one observer (forecast display), then update again
    weatherData.removeObserver(&forecastDisplay);
    weatherData.setMeasurements(24.0f, 60.0f, 1014.0f);

    return 0;
}

results matching ""

    No results matching ""