Usage examples: The Observer pattern is pretty common in C# code, especially in the GUI components. It provides a way to react to events happening in other objects without coupling to their classes.
Identification: The pattern can be recognized by subscription methods, that store objects in a list and by calls to the update method issued to objects in that list.
Conceptual Example
This example illustrates the structure of the Observer design pattern. It focuses on answering these questions:
What classes does it consist of?
What roles do these classes play?
In what way the elements of the pattern are related?
Program.cs: Conceptual example
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading;namespaceRefactoringGuru.DesignPatterns.Observer.Conceptual{publicinterfaceIObserver { // Receive update from subjectvoidUpdate(ISubject subject); }publicinterfaceISubject { // Attach an observer to the subject.voidAttach(IObserver observer); // Detach an observer from the subject.voidDetach(IObserver observer); // Notify all observers about an event.voidNotify(); } // The Subject owns some important state and notifies observers when the // state changes.publicclassSubject:ISubject { // For the sake of simplicity, the Subject's state, essential to all // subscribers, is stored in this variable.publicint State { get; set; } =-0; // List of subscribers. In real life, the list of subscribers can be // stored more comprehensively (categorized by event type, etc.).privateList<IObserver> _observers =newList<IObserver>(); // The subscription management methods.publicvoidAttach(IObserver observer) {Console.WriteLine("Subject: Attached an observer.");this._observers.Add(observer); }publicvoidDetach(IObserver observer) {this._observers.Remove(observer);Console.WriteLine("Subject: Detached an observer."); } // Trigger an update in each subscriber.publicvoidNotify() {Console.WriteLine("Subject: Notifying observers...");foreach (var observer in _observers) {observer.Update(this); } } // Usually, the subscription logic is only a fraction of what a Subject // can really do. Subjects commonly hold some important business logic, // that triggers a notification method whenever something important is // about to happen (or after it).publicvoidSomeBusinessLogic() {Console.WriteLine("\nSubject: I'm doing something important.");this.State=newRandom().Next(0,10);Thread.Sleep(15);Console.WriteLine("Subject: My state has just changed to: "+this.State);this.Notify(); } } // Concrete Observers react to the updates issued by the Subject they had // been attached to.classConcreteObserverA:IObserver {publicvoidUpdate(ISubject subject) { if ((subject asSubject).State<3) {Console.WriteLine("ConcreteObserverA: Reacted to the event."); } } }classConcreteObserverB:IObserver {publicvoidUpdate(ISubject subject) {if ((subject asSubject).State==0|| (subject asSubject).State>=2) {Console.WriteLine("ConcreteObserverB: Reacted to the event."); } } }classProgram {staticvoidMain(string[] args) { // The client code.var subject =newSubject();var observerA =newConcreteObserverA();subject.Attach(observerA);var observerB =newConcreteObserverB();subject.Attach(observerB);subject.SomeBusinessLogic();subject.SomeBusinessLogic();subject.Detach(observerB);subject.SomeBusinessLogic(); } }}
Output.txt: Execution result
Subject: Attached an observer.
Subject: Attached an observer.
Subject: I'm doing something important.
Subject: My state has just changed to: 2
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.
ConcreteObserverB: Reacted to the event.
Subject: I'm doing something important.
Subject: My state has just changed to: 1
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.
Subject: Detached an observer.
Subject: I'm doing something important.
Subject: My state has just changed to: 5
Subject: Notifying observers...