Menu
Coddy logo textTech

Wzorzec obserwatora (zdarzenia)

Część sekcji Programowanie obiektowe ścieżki C# w Coddy. Lekcja 54 z 70.

Wzorzec Obserwatora ustanawia relację jeden-do-wielu, w której jeden obiekt (podmiot) powiadamia wiele zależnych obiektów (obserwatorów), gdy zmienia się jego stan. W języku C# zdarzenia zapewniają wbudowany sposób eleganckiej implementacji tego wzorca.

Wzorzec obejmuje wydawcę, który wywołuje zdarzenia, oraz subskrybentów, którzy na nie reagują. Oto praktyczny przykład monitora cen akcji:

public class Stock
{
    private decimal _price;
    
    public event Action<decimal> PriceChanged;
    
    public decimal Price
    {
        get => _price;
        set
        {
            _price = value;
            PriceChanged?.Invoke(_price);  // Powiadom wszystkich obserwatorów
        }
    }
}

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}");
    }
}

Subskrybenci dołączają swoje metody do zdarzenia za pomocą += i mogą je odłączyć za pomocą -=:

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

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

stock.Price = 150.50m;
// Wynik:
// Alert: Cena wynosi teraz 150.50
// Zarejestrowano: 150.50

stock.PriceChanged -= logger.OnPriceChanged;  // Anuluj subskrypcję
stock.Price = 155.00m;
// Wynik: Alert: Cena wynosi teraz 155.00

Wzorzec Obserwator promuje luźne powiązanie — klasa Stock nie musi nic wiedzieć o swoich obserwatorach. Nowi obserwatorzy mogą się subskrybować bez modyfikowania wydawcy, co ułatwia rozszerzanie i utrzymywanie systemu.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system monitorowania temperatury z wykorzystaniem wzorca Obserwator i zdarzeń. Utworzysz czujnik, który powiadamia wielu obserwatorów za każdym razem, gdy zmienia się temperatura — idealne rozwiązanie w scenariuszach takich jak systemy kontroli klimatu, w których różne komponenty muszą reagować na zmiany temperatury.

Rozmieścisz kod w trzech plikach:

  • TemperatureSensor.cs: Utwórz klasę TemperatureSensor w przestrzeni nazw Monitoring. To Twój wydawca — obiekt obserwowany przez inne obiekty. Twój czujnik powinien mieć:
    • Prywatne pole do przechowywania bieżącej temperatury
    • Zdarzenie o nazwie TemperatureChanged, które używa Action<double> do powiadamiania subskrybentów o nowej temperaturze
    • Właściwość Temperature, która wywołuje zdarzenie za każdym razem, gdy temperatura zostaje ustawiona na nową wartość
  • Observers.cs: Utwórz dwie klasy obserwatorów w tej samej przestrzeni nazw, które będą subskrybować zmiany temperatury:
    • DisplayUnit — ma metodę OnTemperatureChanged(double temp), która wyświetla Display: {temp}C
    • AlarmSystem — ma metodę OnTemperatureChanged(double temp), która wyświetla Alarm Check: {temp}C
  • Program.cs: Połącz wszystko, tworząc czujnik i obu obserwatorów. Zasubskrybuj obu obserwatorów do zdarzenia czujnika, a następnie zaktualizuj temperaturę. Potem anuluj subskrypcję systemu alarmowego i ponownie zaktualizuj temperaturę, aby pokazać, że powiadomienie otrzymuje już tylko wyświetlacz.

Otrzymasz dwa wejścia:

  • Pierwszy odczyt temperatury (np. 22.5)
  • Drugi odczyt temperatury (np. 28.0)

Twój program powinien:

  1. Utworzyć czujnik i obu obserwatorów
  2. Zasubskrybować obu obserwatorów do zdarzenia TemperatureChanged
  3. Ustawić temperaturę czujnika na wartość pierwszego wejścia (powiadomieni powinni zostać obaj obserwatorzy)
  4. Anulować subskrypcję AlarmSystem na zdarzenie
  5. Ustawić temperaturę czujnika na wartość drugiego wejścia (powiadomiony powinien zostać tylko wyświetlacz)

Na przykład, jeśli wejściami są 22.5 i 28.0, wynik powinien być następujący:

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

To pokazuje podstawową zaletę wzorca Obserwator — czujnik nie wie ani nie musi się przejmować tym, kto go nasłuchuje. Obserwatorzy mogą dynamicznie subskrybować i anulować subskrypcję, a wydawca po prostu powiadamia tych, którzy aktualnie nasłuchują!

Spróbuj swoich sił

using System;
using Monitoring;

class Program
{
    public static void Main(string[] args)
    {
        // Odczytaj podane temperatury
        double temp1 = Convert.ToDouble(Console.ReadLine());
        double temp2 = Convert.ToDouble(Console.ReadLine());

        // TODO: Utwórz instancję TemperatureSensor

        // TODO: Utwórz instancje DisplayUnit i AlarmSystem

        // TODO: Zarejestruj obu obserwatorów do obsługi zdarzenia TemperatureChanged

        // TODO: Ustaw temperaturę czujnika na temp1 (obaj obserwatorzy otrzymają powiadomienie)

        // TODO: Wyrejestruj AlarmSystem z obsługi zdarzenia

        // TODO: Ustaw temperaturę czujnika na temp2 (powiadomienie otrzyma tylko wyświetlacz)
    }
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C# online