Observer-Muster (Events)
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 54 von 70.
Das Beobachtermuster stellt eine Eins-zu-viele-Beziehung her, bei der ein Objekt (das Subjekt) mehrere abhängige Objekte (Beobachter) benachrichtigt, wenn sich sein Zustand ändert. In C# bieten Ereignisse eine integrierte Möglichkeit, dieses Muster elegant umzusetzen.
Das Muster umfasst einen Herausgeber, der Ereignisse auslöst, und Abonnenten, die darauf reagieren. Hier ist ein praktisches Beispiel für eine Überwachung von Aktienkursen:
public class Stock
{
private decimal _price;
public event Action<decimal> PriceChanged;
public decimal Price
{
get => _price;
set
{
_price = value;
PriceChanged?.Invoke(_price); // Alle Beobachter benachrichtigen
}
}
}
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}");
}
}Abonnenten hängen ihre Methoden mit += an das Ereignis an und können sie mit -= wieder entfernen:
var stock = new Stock();
var alert = new PriceAlert();
var logger = new PriceLogger();
stock.PriceChanged += alert.OnPriceChanged;
stock.PriceChanged += logger.OnPriceChanged;
stock.Price = 150.50m;
// Ausgabe:
// Warnung: Price beträgt jetzt 150.50
// Protokolliert: 150.50
stock.PriceChanged -= logger.OnPriceChanged; // Abmelden
stock.Price = 155.00m;
// Ausgabe: Warnung: Price beträgt jetzt 155.00Das Observer-Muster fördert eine lose Kopplung – die Klasse Stock muss nichts über ihre Beobachter wissen. Neue Beobachter können sich anmelden, ohne den Herausgeber zu ändern, sodass sich das System leicht erweitern und warten lässt.
Aufgabe
EinfachErstellen wir ein Temperaturüberwachungssystem mit dem Beobachtermuster und Ereignissen. Du erstellst einen Sensor, der mehrere Beobachter benachrichtigt, sobald sich die Temperatur ändert – ideal für Szenarien wie Klimaregelungssysteme, in denen verschiedene Komponenten auf Temperaturänderungen reagieren müssen.
Du organisierst deinen Code auf drei Dateien:
TemperatureSensor.cs: Erstelle eine KlasseTemperatureSensorim NamespaceMonitoring. Das ist dein Herausgeber – das Subjekt, das andere Objekte beobachten. Dein Sensor sollte Folgendes haben:- Ein privates Feld zum Speichern der aktuellen Temperatur
- Ein Ereignis namens
TemperatureChanged, dasAction<double>verwendet, um Abonnenten über die neue Temperatur zu benachrichtigen - Eine Eigenschaft
Temperature, die das Ereignis auslöst, sobald die Temperatur auf einen neuen Wert gesetzt wird
Observers.cs: Erstelle zwei Beobachterklassen im selben Namespace, die Temperaturänderungen abonnieren:DisplayUnit– hat eine MethodeOnTemperatureChanged(double temp), dieDisplay: {temp}CausgibtAlarmSystem– hat eine MethodeOnTemperatureChanged(double temp), dieAlarm Check: {temp}Causgibt
Program.cs: Füge alles zusammen, indem du einen Sensor und beide Beobachter erstellst. Abonniere mit beiden Beobachtern das Ereignis des Sensors und aktualisiere dann die Temperatur. Danach meldest du das Alarmsystem vom Ereignis ab und aktualisierst die Temperatur erneut, um zu zeigen, dass nur die Anzeigeeinheit die Benachrichtigung erhält.
Du erhältst zwei Eingaben:
- Erster Temperaturmesswert (z. B.
22.5) - Zweiter Temperaturmesswert (z. B.
28.0)
Dein Programm sollte Folgendes tun:
- Den Sensor und beide Beobachter erstellen
- Beide Beobachter beim Ereignis
TemperatureChangedabonnieren - Die Temperatur des Sensors auf den ersten Eingabewert setzen (beide Beobachter sollten benachrichtigt werden)
AlarmSystemvom Ereignis abmelden- Die Temperatur des Sensors auf den zweiten Eingabewert setzen (nur die Anzeige sollte benachrichtigt werden)
Wenn die Eingaben beispielsweise 22.5 und 28.0 lauten, sollte die Ausgabe wie folgt aussehen:
Display: 22.5C
Alarm Check: 22.5C
Display: 28CDas zeigt die zentrale Stärke des Beobachtermusters: Der Sensor weiß nicht und muss sich nicht darum kümmern, wer ihm zuhört. Beobachter können sich jederzeit anmelden und abmelden, und der Herausgeber benachrichtigt einfach diejenigen, die gerade zuhören!
Probier es selbst
using System;
using Monitoring;
class Program
{
public static void Main(string[] args)
{
// Eingabetemperaturen einlesen
double temp1 = Convert.ToDouble(Console.ReadLine());
double temp2 = Convert.ToDouble(Console.ReadLine());
// TODO: Eine TemperatureSensor-Instanz erstellen
// TODO: Instanzen von DisplayUnit und AlarmSystem erstellen
// TODO: Beide Beobachter für das TemperatureChanged-Ereignis registrieren
// TODO: Die Temperatur des Sensors auf temp1 setzen (beide Beobachter werden benachrichtigt)
// TODO: AlarmSystem vom Ereignis abmelden
// TODO: Die Temperatur des Sensors auf temp2 setzen (nur DisplayUnit wird benachrichtigt)
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienNamespaces & DirektivenEinführung in Klassen & ObjekteDas 'this'-SchlüsselwortMethoden und ParameterFelder vs. EigenschaftenKonstruktorenObjektinitialisiererWiederholung – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbungs-(:)-SyntaxDas „base“-Schlüsselwort„virtual“- und „override“-SchlüsselwörterVersiegelte KlassenDie „object“-BasisklasseWiederholung – Mitarbeiterhierarchie7Erweiterte Funktionen
Überladen von OperatorenIndexer (this[])ToString()-ÜberschreibungErweiterungsmethodenRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterThread-sicheres SingletonFactory-MusterObserver-Muster (Events)Strategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformKomponente für SpielfigurenFahrzeugvermietungsdienst2Eigenschaften & statische Member
Automatisch implementierte EigenschaftenNur lesbare/schreibbare EigenschaftenStatische Felder & MethodenStatische KlassenMember mit Ausdruckskörpern5Polymorphie & Interfaces
Compile- vs. Laufzeit-PolymorphieInterface vs. abstrakte KlasseMehrere InterfacesExplizite InterfacesUpcasting & DowncastingWiederholung – Formenrechner3Klassenarchitektur
Instanz- vs. statische DatenSchlüsselwörter 'readonly' & 'const'Backing FieldsRückblick – Bankkontenverwaltung6Kapselung
ZugriffsmodifikatorenEigenschaften zur KapselungImplementierung der DatenkapselungMuster für UnveränderlichkeitRückblick – SchülerdatenÜbe selbstständig: Online-C#-Compiler