Observer Pattern (Events)
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy — Lektion 54 von 70.
Das Observer-Muster etabliert eine Eins-zu-viele-Beziehung, bei der ein Objekt (das Subjekt) mehrere abhängige Objekte (Beobachter) benachrichtigt, wenn sich sein Zustand ändert. In C# bieten Events eine integrierte Möglichkeit, dieses Muster elegant zu implementieren.
Das Muster umfasst einen Publisher, der Ereignisse auslöst, und Subscriber, die auf diese reagieren. Hier ist ein praktisches Beispiel für einen Aktienkurs-Monitor:
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 verknüpfen ihre Methoden über += mit dem Ereignis und können diese mit -= wieder trennen:
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:
// Alarm: Preis ist jetzt 150.50
// Protokolliert: 150.50
stock.PriceChanged -= logger.OnPriceChanged; // Abmelden
stock.Price = 155.00m;
// Ausgabe: Alarm: Preis ist jetzt 155.00Das Observer-Muster fördert eine lose Kopplung – die Stock-Klasse muss nichts über ihre Observer wissen. Neue Observer können sich anmelden, ohne den Publisher zu modifizieren, was das System einfach erweiterbar und wartbar macht.
Aufgabe
EinfachLassen Sie uns ein Temperaturüberwachungssystem mit dem Observer-Pattern und Events erstellen. Sie werden einen Sensor erstellen, der mehrere Observer benachrichtigt, wann immer sich die Temperatur ändert – ideal für Szenarien wie Klimasteuerungssysteme, in denen verschiedene Komponenten auf Temperaturaktualisierungen reagieren müssen.
Sie werden Ihren Code in drei Dateien organisieren:
TemperatureSensor.cs: Erstellen Sie eineTemperatureSensor-Klasse im NamespaceMonitoring. Dies ist Ihr Publisher – das Subjekt, das andere Objekte beobachten werden. Ihr Sensor sollte Folgendes haben:- Ein privates Feld zum Speichern der aktuellen Temperatur
- Ein Event namens
TemperatureChanged, dasAction<double>verwendet, um Abonnenten über die neue Temperatur zu benachrichtigen - Eine
Temperature-Eigenschaft, die das Event auslöst, wann immer die Temperatur auf einen neuen Wert gesetzt wird
Observers.cs: Erstellen Sie zwei Observer-Klassen im selben Namespace, die Temperaturänderungen abonnieren werden:DisplayUnit– hat eine MethodeOnTemperatureChanged(double temp), dieDisplay: {temp}CausgibtAlarmSystem– hat eine MethodeOnTemperatureChanged(double temp), dieAlarm Check: {temp}Causgibt
Program.cs: Bringen Sie alles zusammen, indem Sie einen Sensor und beide Observer erstellen. Abonnieren Sie beide Observer für das Event des Sensors und aktualisieren Sie dann die Temperatur. Deabonnieren Sie danach das Alarmsystem und aktualisieren Sie die Temperatur erneut, um zu zeigen, dass nur die Anzeigeeinheit die Benachrichtigung erhält.
Sie erhalten zwei Eingaben:
- Erster Temperaturmesswert (z. B.
22.5) - Zweiter Temperaturmesswert (z. B.
28.0)
Ihr Programm sollte:
- Den Sensor und beide Observer erstellen
- Beide Observer für das Event
TemperatureChangedabonnieren - Die Temperatur des Sensors auf den ersten Eingabewert setzen (beide Observer sollten benachrichtigt werden)
- Das
AlarmSystemvom Event deabonnieren - Die Temperatur des Sensors auf den zweiten Eingabewert setzen (nur die Anzeige sollte benachrichtigt werden)
Wenn die Eingaben beispielsweise 22.5 und 28.0 sind, sollte die Ausgabe wie folgt aussehen:
Display: 22.5C
Alarm Check: 22.5C
Display: 28CDies demonstriert die zentrale Stärke des Observer-Patterns – der Sensor weiß nicht und es ist ihm egal, wer ihm zuhört. Observer können sich dynamisch an- und abmelden, und der Publisher benachrichtigt einfach jeden, der gerade zuhört!
Spickzettel
Das Observer-Muster (Beobachter-Muster) etabliert eine Eins-zu-viele-Beziehung, bei der ein Objekt (das Subjekt) mehrere abhängige Objekte (Beobachter) benachrichtigt, wenn sich sein Zustand ändert.
In C# bieten Events eine integrierte Möglichkeit, dieses Muster zu implementieren. Das Muster umfasst einen Publisher, der Ereignisse auslöst, und Subscriber, die darauf reagieren.
Grundlegende Event-Implementierung
Definieren Sie ein Event mit event Action<T> und rufen Sie es auf, wenn sich der Zustand ändert:
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
}
}
}Beobachter erstellen
Beobachter sind Klassen mit Methoden, die der Event-Signatur entsprechen:
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}");
}
}Subscribing und Unsubscribing
Verwenden Sie += zum Abonnieren und -= zum Abbestellen von Events:
var stock = new Stock();
var alert = new PriceAlert();
var logger = new PriceLogger();
stock.PriceChanged += alert.OnPriceChanged; // Abonnieren
stock.PriceChanged += logger.OnPriceChanged; // Abonnieren
stock.Price = 150.50m; // Beide Beobachter benachrichtigt
stock.PriceChanged -= logger.OnPriceChanged; // Abbestellen
stock.Price = 155.00m; // Nur Alert benachrichtigtDas Observer-Muster fördert eine lose Kopplung – der Publisher muss nichts über seine Beobachter wissen. Neue Beobachter können abonniert werden, ohne den Publisher zu ändern.
Probier es selbst
using System;
using Monitoring;
class Program
{
public static void Main(string[] args)
{
// Eingabetemperaturen lesen
double temp1 = Convert.ToDouble(Console.ReadLine());
double temp2 = Convert.ToDouble(Console.ReadLine());
// TODO: Eine TemperatureSensor-Instanz erstellen
// TODO: DisplayUnit- und AlarmSystem-Instanzen erstellen
// TODO: Beide Observer für das TemperatureChanged-Event registrieren
// TODO: Die Temperatur des Sensors auf temp1 setzen (beide Observer werden benachrichtigt)
// TODO: Das AlarmSystem vom Event abmelden
// TODO: Die Temperatur des Sensors auf temp2 setzen (nur das Display 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. EigenschaftenKonstruktorenObjekt-InitialisiererZusammenfassung - Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (:) SyntaxDas 'base'-SchlüsselwortVirtual & Override SchlüsselwörterVersiegelte KlassenDie 'object'-BasisklasseZusammenfassung – Mitarbeiter-Hierarchie7Fortgeschrittene Funktionen
OperatorüberladungIndexer (this[])ToString() überschreibenErweiterungsmethodenZusammenfassung - Benutzerdefinierte Liste10Design Patterns Teil 1
Einführung in Design PatternsThread-sicheres SingletonFactory PatternObserver Pattern (Events)Strategy Pattern2Eigenschaften & Statische Member
Automatisch implementierte EigenschaftenRead-Only- & Write-Only-EigenschaftenStatische Felder & MethodenStatische KlassenExpression-Bodied Member5Polymorphismus & Interfaces
Compile- vs. Runtime-PolymorphismusInterface vs. abstrakte KlasseMehrfache InterfacesExplizite InterfacesUpcasting & DowncastingRecap – Shape Calculator3Klassenarchitektur
Instanz- vs. statische Daten'readonly' & 'const' SchlüsselwörterBacking FieldsZusammenfassung - Bankkonto-Manager6Kapselung
ZugriffsmodifikatorenProperties zur KapselungImplementierung von Data HidingImmutability-MusterRückblick – Studierendendaten