Wednesday, October 14, 2015

Improve the knowledge about Observer Design Patterns

Definition

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.


UML class diagram







Participants


    The classes and objects participating in this pattern are:
  • Subject  (Stock)
    • knows its observers. Any number of Observer objects may observe a subject
    • provides an interface for attaching and detaching Observer objects.
  • ConcreteSubject  (IBM)
    • stores state of interest to ConcreteObserver
    • sends a notification to its observers when its state changes
  • Observer  (IInvestor)
    • defines an updating interface for objects that should be notified of changes in a subject.
  • ConcreteObserver  (Investor)
    • maintains a reference to a ConcreteSubject object
    • stores state that should stay consistent with the subject's
    • implements the Observer updating interface to keep its state consistent with the subject's



Structural code in C#


This structural code demonstrates the Observer pattern in which registered objects are notified of and updated with a state change.
  1. using System;
  2. using System.Collections.Generic;

  3. namespace DoFactory.GangOfFour.Observer.Structural
  4. {
  5.   /// <summary>
  6.   /// MainApp startup class for Structural
  7.   /// Observer Design Pattern.
  8.   /// </summary>
  9.   class MainApp
  10.   {
  11.     /// <summary>
  12.     /// Entry point into console application.
  13.     /// </summary>
  14.     static void Main()
  15.     {
  16.       // Configure Observer pattern
  17.       ConcreteSubject s = new ConcreteSubject();

  18.       s.Attach(new ConcreteObserver(s, "X"));
  19.       s.Attach(new ConcreteObserver(s, "Y"));
  20.       s.Attach(new ConcreteObserver(s, "Z"));

  21.       // Change subject and notify observers
  22.       s.SubjectState = "ABC";
  23.       s.Notify();

  24.       // Wait for user
  25.       Console.ReadKey();
  26.     }
  27.   }

  28.   /// <summary>
  29.   /// The 'Subject' abstract class
  30.   /// </summary>
  31.   abstract class Subject
  32.   {
  33.     private List<Observer> _observers = new List<Observer>();

  34.     public void Attach(Observer observer)
  35.     {
  36.       _observers.Add(observer);
  37.     }

  38.     public void Detach(Observer observer)
  39.     {
  40.       _observers.Remove(observer);
  41.     }

  42.     public void Notify()
  43.     {
  44.       foreach (Observer o in _observers)
  45.       {
  46.         o.Update();
  47.       }
  48.     }
  49.   }

  50.   /// <summary>
  51.   /// The 'ConcreteSubject' class
  52.   /// </summary>
  53.   class ConcreteSubject : Subject
  54.   {
  55.     private string _subjectState;

  56.     // Gets or sets subject state
  57.     public string SubjectState
  58.     {
  59.       get { return _subjectState; }
  60.       set { _subjectState = value; }
  61.     }
  62.   }

  63.   /// <summary>
  64.   /// The 'Observer' abstract class
  65.   /// </summary>
  66.   abstract class Observer
  67.   {
  68.     public abstract void Update();
  69.   }

  70.   /// <summary>
  71.   /// The 'ConcreteObserver' class
  72.   /// </summary>
  73.   class ConcreteObserver : Observer
  74.   {
  75.     private string _name;
  76.     private string _observerState;
  77.     private ConcreteSubject _subject;

  78.     // Constructor
  79.     public ConcreteObserver(
  80.       ConcreteSubject subject, string name)
  81.     {
  82.       this._subject = subject;
  83.       this._name = name;
  84.     }

  85.     public override void Update()
  86.     {
  87.       _observerState = _subject.SubjectState;
  88.       Console.WriteLine("Observer {0}'s new state is {1}",
  89.         _name, _observerState);
  90.     }

  91.     // Gets or sets subject
  92.     public ConcreteSubject Subject
  93.     {
  94.       get { return _subject; }
  95.       set { _subject = value; }
  96.     }
  97.   }
  98. }
  99.  
  100.  

Output
Observer X's new state is ABC
Observer Y's new state is ABC
Observer Z's new state is ABC





Real-world code in C#


This real-world code demonstrates the Observer pattern in which registered investors are notified every time a stock changes value.
  1. using System;
  2. using System.Collections.Generic;

  3. namespace DoFactory.GangOfFour.Observer.RealWorld
  4. {
  5.   /// <summary>
  6.   /// MainApp startup class for Real-World
  7.   /// Observer Design Pattern.
  8.   /// </summary>
  9.   class MainApp
  10.   {
  11.     /// <summary>
  12.     /// Entry point into console application.
  13.     /// </summary>
  14.     static void Main()
  15.     {
  16.       // Create IBM stock and attach investors
  17.       IBM ibm = new IBM("IBM", 120.00);
  18.       ibm.Attach(new Investor("Sorros"));
  19.       ibm.Attach(new Investor("Berkshire"));

  20.       // Fluctuating prices will notify investors
  21.       ibm.Price = 120.10;
  22.       ibm.Price = 121.00;
  23.       ibm.Price = 120.50;
  24.       ibm.Price = 120.75;

  25.       // Wait for user
  26.       Console.ReadKey();
  27.     }
  28.   }

  29.   /// <summary>
  30.   /// The 'Subject' abstract class
  31.   /// </summary>
  32.   abstract class Stock
  33.   {
  34.     private string _symbol;
  35.     private double _price;
  36.     private List<IInvestor> _investors = new List<IInvestor>();

  37.     // Constructor
  38.     public Stock(string symbol, double price)
  39.     {
  40.       this._symbol = symbol;
  41.       this._price = price;
  42.     }

  43.     public void Attach(IInvestor investor)
  44.     {
  45.       _investors.Add(investor);
  46.     }

  47.     public void Detach(IInvestor investor)
  48.     {
  49.       _investors.Remove(investor);
  50.     }

  51.     public void Notify()
  52.     {
  53.       foreach (IInvestor investor in _investors)
  54.       {
  55.         investor.Update(this);
  56.       }

  57.       Console.WriteLine("");
  58.     }

  59.     // Gets or sets the price
  60.     public double Price
  61.     {
  62.       get { return _price; }
  63.       set
  64.       {
  65.         if (_price != value)
  66.         {
  67.           _price = value;
  68.           Notify();
  69.         }
  70.       }
  71.     }

  72.     // Gets the symbol
  73.     public string Symbol
  74.     {
  75.       get { return _symbol; }
  76.     }
  77.   }

  78.   /// <summary>
  79.   /// The 'ConcreteSubject' class
  80.   /// </summary>
  81.   class IBM : Stock
  82.   {
  83.     // Constructor
  84.     public IBM(string symbol, double price)
  85.       : base(symbol, price)
  86.     {
  87.     }
  88.   }

  89.   /// <summary>
  90.   /// The 'Observer' interface
  91.   /// </summary>
  92.   interface IInvestor
  93.   {
  94.     void Update(Stock stock);
  95.   }

  96.   /// <summary>
  97.   /// The 'ConcreteObserver' class
  98.   /// </summary>
  99.   class Investor : IInvestor
  100.   {
  101.     private string _name;
  102.     private Stock _stock;

  103.     // Constructor
  104.     public Investor(string name)
  105.     {
  106.       this._name = name;
  107.     }

  108.     public void Update(Stock stock)
  109.     {
  110.       Console.WriteLine("Notified {0} of {1}'s " +
  111.         "change to {2:C}", _name, stock.Symbol, stock.Price);
  112.     }

  113.     // Gets or sets the stock
  114.     public Stock Stock
  115.     {
  116.       get { return _stock; }
  117.       set { _stock = value; }
  118.     }
  119.   }
  120. }
  121.  

Output
Notified Sorros of IBM's change to $120.10
Notified Berkshire of IBM's change to $120.10

Notified Sorros of IBM's change to $121.00
Notified Berkshire of IBM's change to $121.00

Notified Sorros of IBM's change to $120.50
Notified Berkshire of IBM's change to $120.50

Notified Sorros of IBM's change to $120.75
Notified Berkshire of IBM's change to $120.75

No comments:

Post a Comment