Patron Observateur (Événements)
Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy. Leçon 54 sur 70.
Le modèle Observateur établit une relation un-à-plusieurs dans laquelle un objet (le sujet) informe plusieurs objets dépendants (les observateurs) lorsque son état change. En C#, les événements offrent un moyen intégré de mettre en œuvre élégamment ce modèle.
Le modèle implique un éditeur qui déclenche des événements et des abonnés qui y réagissent. Voici un exemple pratique de surveillance du cours d’une action :
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 associent leurs méthodes à l’événement à l’aide de += et peuvent les dissocier 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
// Enregistré : 150.50
stock.PriceChanged -= logger.OnPriceChanged; // Se désabonner
stock.Price = 155.00m;
// Sortie : Alerte : le prix est maintenant de 155.00Le modèle Observer favorise un faible couplage : la classe Stock n’a pas besoin de connaître quoi que ce soit au sujet de ses observateurs. De nouveaux observateurs peuvent s’abonner sans modifier le diffuseur, ce qui facilite l’extension et la maintenance du système.
Défi
FacileConstruisons un système de surveillance de la température à l’aide du modèle Observateur avec des événements. Tu vas créer un capteur qui notifie plusieurs observateurs chaque fois que la température change — idéal pour des situations comme les systèmes de régulation climatique, où différents composants doivent réagir aux mises à jour de température.
Tu vas répartir ton code dans trois fichiers :
TemperatureSensor.cs: crée une classeTemperatureSensordans l’espace de nomsMonitoring. C’est ton éditeur — le sujet que les autres objets observeront. Ton capteur doit avoir :- Un champ privé pour stocker la température actuelle
- Un événement appelé
TemperatureChangedqui utiliseAction<double>pour informer les abonnés de la nouvelle température - Une propriété
Temperaturequi déclenche l’événement chaque fois que la température est définie sur une nouvelle valeur
Observers.cs: crée deux classes d’observateurs dans le même espace de noms, qui s’abonneront aux changements de température :DisplayUnit— possède une méthodeOnTemperatureChanged(double temp)qui afficheDisplay: {temp}CAlarmSystem— possède une méthodeOnTemperatureChanged(double temp)qui afficheAlarm Check: {temp}C
Program.cs: rassemble le tout en créant un capteur et les deux observateurs. Abonne les deux observateurs à l’événement du capteur, puis mets à jour la température. Ensuite, désabonne le système d’alarme et mets de nouveau à jour la température afin de montrer que seule l’unité d’affichage reçoit la notification.
Tu recevras deux valeurs en entrée :
- Première mesure de température (par exemple,
22.5) - Deuxième mesure de température (par exemple,
28.0)
Ton programme doit :
- Créer le capteur et les deux observateurs
- Abonner les deux observateurs à l’événement
TemperatureChanged - Définir la température du capteur sur la première valeur d’entrée (les deux observateurs doivent être notifiés)
- Désabonner
AlarmSystemde l’événement - Définir la température du capteur sur la deuxième valeur d’entrée (seule l’unité d’affichage doit être notifiée)
Par exemple, si les valeurs d’entrée sont 22.5 et 28.0, la sortie doit être :
Display: 22.5C
Alarm Check: 22.5C
Display: 28CCela illustre la force fondamentale du modèle Observateur : le capteur ne sait pas et ne se soucie pas de ce qui l’écoute. Les observateurs peuvent s’abonner et se désabonner dynamiquement, et l’éditeur se contente de notifier ceux qui l’écoutent à ce moment-là !
Essayez vous-même
using System;
using Monitoring;
class Program
{
public static void Main(string[] args)
{
// Lire les températures en 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 de AlarmSystem
// TODO: Abonner les deux observateurs à l’événement TemperatureChanged
// TODO: Définir la température du capteur sur temp1 (les deux observateurs sont notifiés)
// TODO: Désabonner AlarmSystem de l’événement
// TODO: Définir la température du capteur sur temp2 (seul l’affichage est notifié)
}
}
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
1Fondamentaux de la POO
Fichiers externesEspaces de noms et directivesIntro aux classes et objetsLe mot-clé 'this'Méthodes et paramètresChamps vs PropriétésConstructeursInitialiseurs d'objetsRécapitulatif - Calculatrice simple4Héritage
Syntaxe de base de l'héritage (:)Le mot-clé 'base'Mots-clés Virtual & OverrideClasses scelléesLa classe de base 'object'Récapitulatif - Hiérarchie des employés7Fonctionnalités avancées
Surcharge d'opérateursIndexeurs (this[])Redéfinition de ToString()Méthodes d'extensionRécapitulatif - Liste personnalisée10Patrons de conception - Partie 1
Introduction aux patrons de conceptionSingleton Thread-SafePatron FabriquePatron Observateur (Événements)Patron Stratégie2Propriétés et membres statiques
Propriétés auto-implémentéesPropriétés en lecture/écriture seuleChamps et méthodes statiquesClasses statiquesMembres à corps d'expression5Polymorphisme & Interfaces
Polymorphisme : Compilation vs ExécutionInterface vs Classe AbstraiteInterfaces MultiplesInterfaces ExplicitesUpcasting & DowncastingRécapitulatif - Calculateur de Formes8Concepts avancés de la POO
Composition plutôt qu'héritageGénériques (Classes et Méthodes)Délégués et ÉvénementsAttributs et RéflexionIDisposable et l'instruction usingBases de l'Injection de Dépendances11Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode TemplatePatron ÉtatPatron Composite3Architecture des classes
Données d'instance vs statiquesMots-clés 'readonly' & 'const'Champs de supportRécapitulatif - Gestionnaire de compte bancaire6Encapsulation
Modificateurs d'accèsPropriétés pour l'encapsulationImplémentation du masquage de donnéesPatterns d'immuabilitéRécapitulatif - Dossiers d'étudiants12Projet : Système de gestion de bibliothèque
Structure du projetModèles Livre et UtilisateurLogique du système d'empruntLINQ pour la rechercheInterface Console / Interface d'administrationTests unitaires (NUnit/xUnit)Entraînez-vous par vous-même : Compilateur C# en ligne