CSharp:Design Pattern Observer
From Aino Wiki
Contents
Introduzione
E' un Pattern comportamentale.
Definisce una dipendenza uno a molti tra oggetti così che se un oggetto cambia il proprio stato, tutti i suoi dipendenti sono avvisati con notifiche ed in definitiva aggiornati automaticamente. Semplicemente: un cambiamento in un oggetto causa il cambiamento o una azione in un altro.
Esempio
Materiale ottenuto dal video corso su Lynda.com di LinkedIn.
Diagramma delle classi generico applicabile a qualsiasi esempio di applicazione dell'Observer:
Scenario concreto.
Faremo il caso di un Publisher (un blogger ad es.) e i suoi Subscriber (followers, gente che vuol conoscere i nuovi post\pubblicazioni e quindi vuol essere avvsata). Il pattern è applicabile in quanto al cambiamento di stato del Pubblisher, per nuovo articolo pubblicato, vogliamo che i Subscriber siano avvisati.
Altro buon esempio è nel sistema operativo Windows con quel che è implementato con l'event handling oppure col trigger del click del Mouse.
Codice
Come esempio si sceglie una applicazione Consol che avvisa tutti i fans (subscrivers) di una celebrità nel momento in cui questo pubblica un Twit.
In questa implementazione vogliamo porre l'attenzione al processo che conduce alle notifiche di nuovi eventi (cambio di stato) e non alla notifica che è una semplice scrittura sulla console.
Classe Subject
E' la classe assegnata all'attore che si vuol tenere sott'occhio.
Nella seguente classe di interfaccia si predispongono gli attributi ed i metodi del soggetto\oggetto attore dei cambiamenti di stato da sottoscrivere.
In ICelebrity.cs:
namespace ObserverPattern { // Subject public interface ICelebrity { string FullName { get; } // Nome della celebrità da seguire string Tweet { get; set; } // Testo del twit void Notify(string tweet); // Metodo\Azione di Notifica void AddFollower(IFan fan); // Metodo per aggiungere un fan / sottoscrittore void RemoveFollower(IFan fan); // Metodo per rimuovere un fan / sottoscrittore } }
Classe Observer
Si definisce l'azione di cambio stato, l'Update() che concretamente si implementerà con una scrittura in Console. In IFan.cs:
namespace ObserverPattern { // Observer public interface IFan { void Update(ICelebrity celebrity); } }
Classi ConcreteObserver
In Fan.cs:
namespace ObserverPattern { // Concrete Observer public class Fan : IFan { public void Update(ICelebrity celebrity) { Console.WriteLine($"Fan notified. Tweet of {celebrity.FullName}: " + $"{celebrity.Tweet}"); } } }
Classi ConcreteSubject
Qui ci sarano le concrete implementazioni degli attori ovvero le celebrità di cui si vuol conoscere i nuovi Twit pubblicati.
In GClooney.cs:
namespace ObserverPattern { // Concrete Subject public class GClooney : ICelebrity { private readonly List<IFan> _fans = new List<IFan>(); // Collection private string _tweet; // Backing field public GClooney(string tweet){ // Constructor _tweet = tweet; } public string FullName => "George Clooney"; public string Tweet { get{ return _tweet;} set { Notify(value); } } public void AddFollower(IFan fan) { _fans.Add(fan); } public void RemoveFollower(IFan fan) { _fans.Remove(fan); } public void Notify(string tweet) { _tweet = tweet; foreach (var fan in _fans) { fan.Update(this); } } } }
In TSwift.cs si implementa la notifica in modo più complesso ovvero definendo un evento e le sue notifiche mediante degli handler che li intercettino.
namespace ObserverPattern { public class TSwift : ICelebrity { private string _tweet; private delegate void TweetUpdate(ICelebrity celebrity); private event TweetUpdate OnTweetUpdate; public TSwift(string tweet) { _tweet = tweet; } public string FullName => "Taylor Swift"; public string Tweet { get { return _tweet; } set { Notify(value); } } public void Notify(string tweet) { _tweet = tweet; if (OnTweetUpdate!=null) { OnTweetUpdate(this); } } public void AddFollower(IFan fan) { OnTweetUpdate += fan.Update; } public void RemoveFollower(IFan fan) { OnTweetUpdate -= fan.Update; } } }
Main
In Program.cs:
class Program { static void Main(string[] args) { var gClooney = new GClooney("I love my new wife"); var tSwift = new TSwift("1981 is now my favorite number."); var firstFan = new Fan(); var secondFan = new Fan(); gClooney.AddFollower(firstFan); tSwift.AddFollower(secondFan); gClooney.Tweet = "My wife didn't force me to tweet."; tSwift.Tweet = "I love my new music."; Console.Read(); } }
Mappa e Link
C# | Design Pattern | Teoria
Parole chiave: