Aug 17, 2013

Observer Design Pattern

1 comment
The Observer Design Pattern allows us to have a publisher-subscriber framework, whereas change to a publisher will notify all of its subscribers automatically. The subscribers are registered to the publisher so that when a change occurs in the publisher, all of the subscribers are notified.

 The publishers and the subscribers are decoupled through the use of interfaces. So that the development of each can vary independently.

There are 2 parts in the observer pattern:
  1. The first are the subjects. They are the publishers. When a change occurs to a subject it should notify all of its subscribers.
  2. The second are the observers. They are the subscribers. They simply listen to the changes in the subjects. 
Pattern involved is also called as publish-subscribe pattern. Model view controller (MVC) architecture’s core uses the observer design pattern.  
UML Class Diagram
Scenario for Observer Pattern Usage 
  • When multiple objects depend on state of one object and all these multiple objects should be in sync with the state of this one object then, observer design pattern is the right choice to apply.
  • Consider an excel sheet, data is shown to the user in different views. Generally data is shown in grid cells and as required different graphs, charts can be created for same data. Underlying data is same and when that data (subject) state changes all the different views are updated.
Example
Let us take a stock and investor example for sample implementation. Assume that there is a Stock and investors added it to their market watch for monitoring price changes.

When price is changed in the stock exchange, it will send update to the registered investors saying a value is changed. Then the investors will take decision to buy or sell. In this example, STOCK is the subject and INVESTOR is the observer.  

Implementation
public interface IInvestor
    {
        void Notify(Stock stock);
    }

Implement IInvestor interface
public class Investor : IInvestor
    {
        private string _name;
        private Stock _stock;

        public Stock Stock
        {
            get { return _stock; }
            set { _stock = value; }
        }

        public Investor(string name)
        {
            _name = name;
        }

        public void Notify(Stock stock)
        {
            Console.WriteLine("Notified {0} about {1}'s " + "change to {2:C}",
                _name, stock.Symbol, stock.Price);
        }
    }

Create an abstract stock class
using System;
using System.Collections.Generic;

namespace DesignPatterns.Observer
{
    public abstract class Stock
    {
        private List _investors = new List();
        private string _symbol;
        private double _price;

        public double Price
        {
            get { return _price; }
            set
            {
                if (_price == value)
                    return;
                _price = value;
                Notify();
            }
        }

        public string Symbol
        {
            get { return _symbol; }
        }

        public Stock(string symbol, double price)
        {
            _symbol = symbol;
            _price = price;
        }

        public void Attach(IInvestor investor)
        {
            _investors.Add(investor);
        }

        public void Detach(IInvestor investor)
        {
            _investors.Remove(investor);
        }

        public void Notify()
        {
            foreach (IInvestor investor in _investors)
                investor.Notify(this);
        }
    }
}

Implement stock class
public class Bhel : Stock
    {
        public Bhel(string symbol, double price)
            : base(symbol, price)
        {
        }
    }

Create a client to use above observer pattern,
private void btnObserver_Click(object sender, EventArgs e)
        {
            // Create stock and add investors
            Bhel ibm = new Bhel("BHEL", 180.00);
            ibm.Attach(new Investor("SBI"));
            ibm.Attach(new Investor("LIC"));

            // Changing prices will notify investors
            ibm.Price = 181.25;
            ibm.Price = 185.50;
            ibm.Price = 180.30;
        }

Output 
Notified SBI about BHEL's change to $181.25
Notified LIC about BHEL's change to $181.25

 Notified SBI about BHEL's change to $185.50
 Notified LIC about BHEL's change to $185.50

Notified SBI about BHEL's change to $180.30
Notified LIC about BHEL's change to $180.30

1 comment :