Menu
Coddy logo textTech

Patron Observateur (Événements)

Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy — leçon 54 sur 70.

Le patron de conception Observateur établit une relation de type un-à-plusieurs où un objet (le sujet) notifie plusieurs objets dépendants (les observateurs) lorsque son état change. En C#, les événements fournissent un moyen intégré d'implémenter ce patron de manière élégante.

Le modèle implique un éditeur qui émet des événements et des abonnés qui y répondent. Voici un exemple pratique d'un moniteur de prix d'actions :

public class Stock
{
    private decimal _price;
    
    public event Action<decimal> PriceChanged;
    
    public decimal Price
    {
        get => _price;
        set
        {
            _price = value;
            PriceChanged?.Invoke(_price);  // Notifier tous les observateurs
        }
    }
}

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

Les abonnés attachent leurs méthodes à l'événement en utilisant += et peuvent s'en détacher avec -= :

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

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

stock.Price = 150.50m;
// Sortie :
// Alerte : Le prix est maintenant de 150.50
// Journalisé : 150.50

stock.PriceChanged -= logger.OnPriceChanged;  // Se désabonner
stock.Price = 155.00m;
// Sortie : Alerte : Le prix est maintenant de 155.00

Le pattern Observer favorise un couplage faible - la classe Stock n'a pas besoin de connaître quoi que ce soit sur ses observateurs. De nouveaux observateurs peuvent s'abonner sans modifier l'éditeur, ce qui rend le système facile à étendre et à maintenir.

challenge icon

Défi

Facile

Construisons un système de surveillance de la température en utilisant le motif Observer avec des événements. Vous allez créer un capteur qui notifie plusieurs observateurs chaque fois que la température change - idéal pour des scénarios comme les systèmes de contrôle climatique où différents composants doivent réagir aux mises à jour de température.

Vous organiserez votre code sur trois fichiers :

  • TemperatureSensor.cs : Créez une classe TemperatureSensor dans l'espace de noms Monitoring. C'est votre éditeur - le sujet que d'autres objets observeront. Votre capteur doit avoir :
    • Un champ privé pour stocker la température actuelle
    • Un événement appelé TemperatureChanged qui utilise Action<double> pour notifier les abonnés de la nouvelle température
    • Une propriété Temperature qui déclenche l'événement chaque fois que la température est définie sur une nouvelle valeur
  • Observers.cs : Créez deux classes d'observateurs dans le même espace de noms qui s'abonneront aux changements de température :
    • DisplayUnit - possède une méthode OnTemperatureChanged(double temp) qui affiche Display: {temp}C
    • AlarmSystem - possède une méthode OnTemperatureChanged(double temp) qui affiche Alarm Check: {temp}C
  • Program.cs : Rassemblez le tout en créant un capteur et les deux observateurs. Abonnez les deux observateurs à l'événement du capteur, puis mettez à jour la température. Après cela, désabonnez le système d'alarme et mettez à jour la température à nouveau pour montrer que seule l'unité d'affichage reçoit la notification.

Vous recevrez deux entrées :

  • Première lecture de température (par exemple, 22.5)
  • Deuxième lecture de température (par exemple, 28.0)

Votre programme doit :

  1. Créer le capteur et les deux observateurs
  2. Abonner les deux observateurs à l'événement TemperatureChanged
  3. Définir la température du capteur sur la première valeur d'entrée (les deux observateurs doivent être notifiés)
  4. Désabonner le AlarmSystem de l'événement
  5. Définir la température du capteur sur la deuxième valeur d'entrée (seul l'affichage doit être notifié)

Par exemple, si les entrées sont 22.5 et 28.0, la sortie doit être :

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

Cela démontre la puissance fondamentale du motif Observer - le capteur ne sait pas et ne se soucie pas de qui l'écoute. Les observateurs peuvent s'abonner et se désabonner dynamiquement, et l'éditeur notifie simplement quiconque écoute actuellement !

Aide-mémoire

Le patron de conception Observateur (Observer pattern) établit une relation de un à plusieurs où un objet (le sujet) notifie plusieurs objets dépendants (les observateurs) lorsque son état change.

En C#, les événements fournissent un moyen intégré d'implémenter ce patron. Le modèle implique un éditeur (publisher) qui déclenche des événements et des abonnés (subscribers) qui y répondent.

Implémentation de base d'un événement

Définissez un événement en utilisant event Action<T> et invoquez-le lorsque l'état change :

public class Stock
{
    private decimal _price;
    
    public event Action<decimal> PriceChanged;
    
    public decimal Price
    {
        get => _price;
        set
        {
            _price = value;
            PriceChanged?.Invoke(_price);  // Notify all observers
        }
    }
}

Création des observateurs

Les observateurs sont des classes avec des méthodes qui correspondent à la signature de l'événement :

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

S'abonner et se désabonner

Utilisez += pour s'abonner et -= pour se désabonner des événements :

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

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

stock.Price = 150.50m;  // Both observers notified

stock.PriceChanged -= logger.OnPriceChanged;   // Unsubscribe

stock.Price = 155.00m;  // Only alert notified

Le patron Observateur favorise un couplage faible : l'éditeur n'a pas besoin de connaître quoi que ce soit sur ses observateurs. De nouveaux observateurs peuvent s'abonner sans modifier l'éditeur.

Essayez vous-même

using System;
using Monitoring;

class Program
{
    public static void Main(string[] args)
    {
        // Lire les températures d'entrée
        double temp1 = Convert.ToDouble(Console.ReadLine());
        double temp2 = Convert.ToDouble(Console.ReadLine());

        // TODO: Créer une instance de TemperatureSensor

        // TODO: Créer des instances de DisplayUnit et AlarmSystem

        // TODO: Abonner les deux observateurs à l'événement TemperatureChanged

        // TODO: Régler la température du capteur sur temp1 (les deux observateurs sont notifiés)

        // TODO: Désabonner le AlarmSystem de l'événement

        // TODO: Régler la température du capteur sur temp2 (seul l'affichage est notifié)
    }
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet