Menu
Coddy logo textTech

Pattern Observer (eventi)

Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 54 di 70.

Il pattern Observer stabilisce una relazione uno-a-molti in cui un oggetto (il soggetto) notifica più oggetti dipendenti (osservatori) quando il suo stato cambia. In C#, gli eventi offrono un modo integrato per implementare questo pattern con eleganza.

Il modello prevede un editore che genera eventi e degli iscritti che vi rispondono. Ecco un esempio pratico di monitoraggio del prezzo di un'azione:

public class Stock
{
    private decimal _price;
    
    public event Action<decimal> PriceChanged;
    
    public decimal Price
    {
        get => _price;
        set
        {
            _price = value;
            PriceChanged?.Invoke(_price);  // Notifica tutti gli osservatori
        }
    }
}

public class PriceAlert
{
    public void OnPriceChanged(decimal newPrice)
    {
        Console.WriteLine($"Alert: Price is now {newPrice}");
    }
}

public class PriceLogger
{
    public void OnPriceChanged(decimal newPrice)
    {
        Console.WriteLine($"Logged: {newPrice}");
    }
}

Gli iscritti associano i propri metodi all'evento usando += e possono scollegarli con -=:

var stock = new Stock();
var alert = new PriceAlert();
var logger = new PriceLogger();

stock.PriceChanged += alert.OnPriceChanged;
stock.PriceChanged += logger.OnPriceChanged;

stock.Price = 150.50m;
// Output:
// Avviso: il prezzo è ora 150.50
// Registrato: 150.50

stock.PriceChanged -= logger.OnPriceChanged;  // Annulla l'iscrizione
stock.Price = 155.00m;
// Output: Avviso: il prezzo è ora 155.00

Il pattern Observer favorisce un accoppiamento debole: la classe Stock non deve sapere nulla dei suoi osservatori. Nuovi osservatori possono iscriversi senza modificare il publisher, rendendo il sistema facile da estendere e mantenere.

challenge icon

Sfida

Facile

Costruiamo un sistema di monitoraggio della temperatura usando il pattern Observer con gli eventi. Creerai un sensore che notifica più osservatori ogni volta che la temperatura cambia: è perfetto per scenari come i sistemi di climatizzazione, in cui diversi componenti devono reagire agli aggiornamenti della temperatura.

Organizzerai il codice in tre file:

  • TemperatureSensor.cs: crea una classe TemperatureSensor nello spazio dei nomi Monitoring. Questo è il publisher, ovvero il soggetto osservato dagli altri oggetti. Il sensore deve avere:
    • Un campo privato per memorizzare la temperatura corrente
    • Un evento chiamato TemperatureChanged che usa Action<double> per notificare agli iscritti la nuova temperatura
    • Una proprietà Temperature che genera l'evento ogni volta che la temperatura viene impostata su un nuovo valore
  • Observers.cs: crea due classi osservatore nello stesso spazio dei nomi, che si iscriveranno alle variazioni di temperatura:
    • DisplayUnit - ha un metodo OnTemperatureChanged(double temp) che stampa Display: {temp}C
    • AlarmSystem - ha un metodo OnTemperatureChanged(double temp) che stampa Alarm Check: {temp}C
  • Program.cs: metti insieme tutti gli elementi creando un sensore e entrambi gli osservatori. Iscrivi entrambi gli osservatori all'evento del sensore, quindi aggiorna la temperatura. Dopodiché, annulla l'iscrizione del sistema di allarme e aggiorna nuovamente la temperatura per mostrare che solo l'unità display riceve la notifica.

Riceverai due input:

  • Prima lettura della temperatura (ad es., 22.5)
  • Seconda lettura della temperatura (ad es., 28.0)

Il programma deve:

  1. Creare il sensore e entrambi gli osservatori
  2. Iscrivere entrambi gli osservatori all'evento TemperatureChanged
  3. Impostare la temperatura del sensore sul valore del primo input (entrambi gli osservatori devono ricevere una notifica)
  4. Annullare l'iscrizione di AlarmSystem all'evento
  5. Impostare la temperatura del sensore sul valore del secondo input (solo il display deve ricevere una notifica)

Ad esempio, se gli input sono 22.5 e 28.0, l'output deve essere:

Display: 22.5C
Alarm Check: 22.5C
Display: 28C

Questo dimostra il potenziale fondamentale del pattern Observer: al sensore non interessa sapere chi lo sta ascoltando. Gli osservatori possono iscriversi e annullare l'iscrizione dinamicamente, e il publisher si limita a notificare chiunque sia attualmente in ascolto!

Provalo tu

using System;
using Monitoring;

class Program
{
    public static void Main(string[] args)
    {
        // Leggi le temperature in ingresso
        double temp1 = Convert.ToDouble(Console.ReadLine());
        double temp2 = Convert.ToDouble(Console.ReadLine());

        // TODO: Crea un'istanza di TemperatureSensor

        // TODO: Crea istanze di DisplayUnit e AlarmSystem

        // TODO: Iscrivi entrambi gli osservatori all'evento TemperatureChanged

        // TODO: Imposta la temperatura del sensore su temp1 (entrambi gli osservatori ricevono una notifica)

        // TODO: Annulla l'iscrizione di AlarmSystem all'evento

        // TODO: Imposta la temperatura del sensore su temp2 (solo il display riceve una notifica)
    }
}
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