Menu
Coddy logo textTech

Pattern Observer

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 94 di 104.

Il pattern Observer definisce una dipendenza uno-a-molti tra oggetti: quando un oggetto (il soggetto) cambia stato, tutti i suoi dipendenti (gli osservatori) vengono notificati automaticamente. È ideale per i sistemi di eventi, gli aggiornamenti dell'interfaccia utente o qualsiasi scenario in cui più oggetti devono reagire ai cambiamenti.

Il pattern coinvolge due ruoli chiave: un Soggetto che mantiene un elenco di osservatori e li notifica, e gli Osservatori che implementano un'interfaccia di aggiornamento:

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

class Observer {
public:
    virtual void update(int value) = 0;
    virtual ~Observer() = default;
};

class Subject {
    std::vector<Observer*> observers;
    int state = 0;
    
public:
    void attach(Observer* obs) {
        observers.push_back(obs);
    }
    
    void detach(Observer* obs) {
        observers.erase(
            std::remove(observers.begin(), observers.end(), obs),
            observers.end());
    }
    
    void setState(int value) {
        state = value;
        notify();
    }
    
    void notify() {
        for (Observer* obs : observers) {
            obs->update(state);
        }
    }
};

class Display : public Observer {
    std::string name;
public:
    Display(const std::string& n) : name(n) {}
    void update(int value) override {
        std::cout << name << " received: " << value << "\n";
    }
};

int main() {
    Subject sensor;
    Display screen1("Screen1"), screen2("Screen2");
    
    sensor.attach(&screen1);
    sensor.attach(&screen2);
    sensor.setState(42);  // Entrambi i display sono stati avvisati
}

Quando viene chiamato setState(), il soggetto scorre tutti gli osservatori registrati e chiama il loro metodo update(). Gli osservatori possono collegarsi o scollegarsi in qualsiasi momento, rendendo il sistema flessibile e debolmente accoppiato.

Usa Observer quando le modifiche a un oggetto richiedono l'aggiornamento di altri e non vuoi che questi oggetti siano strettamente accoppiati tra loro.

challenge icon

Sfida

Facile

Costruiamo un sistema di monitoraggio della stazione meteorologica usando il pattern Observer. Creerai una stazione meteorologica che monitora i dati della temperatura e notifica automaticamente più unità di visualizzazione ogni volta che la temperatura cambia: una classica applicazione reale di questo pattern.

Organizzerai il codice in tre file:

  • Observer.h: Definisci l’interfaccia dell’observer e un observer concreto per la visualizzazione.

    Crea una classe astratta Observer con un metodo virtuale puro update(double temperature) che gli observer implementano per ricevere notifiche, insieme a un distruttore virtuale.

    Poi crea una classe TemperatureDisplay che eredita da Observer. Ogni display ha un nome (stringa) impostato tramite il costruttore. Quando viene chiamato update(), dovrebbe stampare:

    [DisplayName]: Temperature is [temperature] degrees
  • WeatherStation.h: Crea il subject che mantiene la temperatura e notifica gli observer.

    La tua classe WeatherStation dovrebbe:

    • Memorizzare un elenco di puntatori agli observer e la temperatura corrente (inizializzata a 0.0)
    • Avere un metodo attach(Observer* obs) per registrare gli observer
    • Avere un metodo detach(Observer* obs) per rimuovere gli observer
    • Avere un metodo setTemperature(double temp) che aggiorna la temperatura e notifica tutti gli observer collegati
    • Avere un metodo privato notify() che chiama update() su ciascun observer passando la temperatura corrente
  • main.cpp: Mostra il pattern Observer in azione.

    Leggi tre input:

    1. Il nome del primo display (stringa)
    2. Il nome del secondo display (stringa)
    3. Un valore di temperatura (double)

    Crea una WeatherStation e due oggetti TemperatureDisplay con i nomi forniti. Collega entrambi i display alla stazione, poi imposta la temperatura sul valore di input. Entrambi i display dovrebbero ricevere automaticamente l’aggiornamento e stampare i propri messaggi.

    Dopodiché, scollega il primo display e imposta una nuova temperatura superiore di 5 gradi rispetto al valore di input. Solo il secondo display dovrebbe ricevere questo aggiornamento.

Per esempio, con gli input Kitchen, Bedroom e 22.5:

Kitchen: Temperature is 22.5 degrees
Bedroom: Temperature is 22.5 degrees
Bedroom: Temperature is 27.5 degrees

Con gli input Office, Lobby e 18.0:

Office: Temperature is 18 degrees
Lobby: Temperature is 18 degrees
Lobby: Temperature is 23 degrees

Nota come il pattern Observer crea un sistema debolmente accoppiato: la stazione meteorologica non deve sapere nulla dei display specifici, si limita a notificare chiunque sia in ascolto. Quando scolleghi un observer, smette automaticamente di ricevere aggiornamenti.

Provalo tu

#include <iostream>
#include <string>
#include "WeatherStation.h"

using namespace std;

int main() {
    // Leggi i dati di input
    string display1Name, display2Name;
    double temperature;
    
    cin >> display1Name;
    cin >> display2Name;
    cin >> temperature;
    
    // TODO: Crea un oggetto WeatherStation
    
    // TODO: Crea due oggetti TemperatureDisplay con i nomi forniti in input
    
    // TODO: Collega entrambi i display alla stazione meteorologica
    
    // TODO: Imposta la temperatura sul valore fornito in input
    // (Entrambi i display dovrebbero stampare i propri messaggi)
    
    // TODO: Scollega il primo display
    
    // TODO: Imposta la temperatura a 5 gradi in più rispetto al valore fornito in input
    // (Solo il secondo display dovrebbe stampare)
    
    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C++ online