Friday, June 1, 2018

Observer Pattern


Observer design pattern is most suitable for publishing notification to its subscribers. Observer pattern also known as publisher-subscriber scenario where publisher notifies change to its all subscribers. Observer Pattern falls under behavioral pattern of GOF (Gang of Four) patterns.

When to use –


Observer pattern used when you have subject, which observed by many observers. When subject’s state changed, it notifies to all its subscribers. The observers register with subject (provider), and whenever the change occurs in subject (provider), the subject (provider) automatically notifies all observers.

To simplify Observer pattern, I have used most common example of stock price change notification. In this example, the watcher can register to watch on any stocks and whenever the stock price changes, the watcher will get notify.

Major components of Observer pattern –


Observer – This interface defines an update operation. This update operation will be called when subject’s state changes.
Concrete Observer – The class implements observer interface and implements actual update operation.
Subject – Subject is an abstract class. It has information about its observers. It also provides mechanism to subscribe and unsubscribe observers.
Concrete Subject – This class maintains its own state and calls base class notify method to update its observers.

Let’s have a look on below example of Observer design pattern.

Code –
//Observer
public interface IStockPriceWatcher
{
    string Name { get; set; }
    Subject Subject { get; set; }
    void Update(Subject sub);
}
//concrete observer
public class Watcher : IStockPriceWatcher
{
    public string Name { get; set; }
    public Subject Subject { get ; set ; }
    public Watcher(string name)
    {
        Name = name;
    }
    public void Update(Subject sub)
    {
        Console.WriteLine("{0}, {1} price udated to {2}",Name, Subject.Name, Subject.Price);
    }
}
//subject
public abstract class Subject
{
    private string name;
    private double price;
    private List<IStockPriceWatcher> investors = new List<IStockPriceWatcher>();
    public Subject(string Name, double Price)
    {
        name = Name;
        price = Price;
    }
    public string Name
    {
        get { return name; }
    }
    public double Price
    {
        get { return price; }
        set
        {
            if (price != value)
            {
                price = value;
                Notify();
            }
        }
    }
    public void Subscribe(IStockPriceWatcher observer)
    {
        investors.Add(observer);
        observer.Subject = this;
        Console.WriteLine("{0} subscribed to {1}", observer.Name, name);
    }
    public void UnSubscribe(IStockPriceWatcher observer)
    {
        investors.Remove(observer);
        Console.WriteLine("{0} unsubscribed from {1}", observer.Name, name );
    }
    public void Notify()
    {
        investors.ForEach(x => x.Update(this));
    }
}
//concrete subject
public class TCS : Subject
{
    public TCS(string name, double price) :base (name, price) { }
}
//concrete subject
public class Infosys : Subject
{
    public Infosys(string name, double price) : base(name, price) { }
}
//concrete subject
public class Wipro : Subject
{
    public Wipro(string name, double price) : base(name, price) { }
}
class Program
{
    static void Main(string[] args)
    {
        //subjects
        TCS tcs = new TCS("TCS", 3000);
        Infosys infy = new Infosys("Infosys", 1100);
        Wipro wipro = new Wipro("Wipro", 350);

        //watchers
        Watcher watcher1 = new Watcher("Watcher1");
        Watcher watcher2 = new Watcher("Watcher2");
        Watcher watcher3 = new Watcher("Watcher3");

        Console.WriteLine(new string('-',30));
        tcs.Subscribe(watcher1);
        infy.Subscribe(watcher2);
        wipro.Subscribe(watcher3);

        Console.WriteLine(new string('-', 30));
        tcs.Price = 3100;
        infy.Price = 1050;
        wipro.Price = 355;

        Console.WriteLine(new string('-', 30));
        tcs.UnSubscribe(watcher1);
        infy.UnSubscribe(watcher2);

        Console.WriteLine(new string('-', 30));
        tcs.Price = 3170;
        infy.Price = 1060;

        Console.WriteLine(new string('-', 30));
        tcs.Subscribe(watcher2);
        infy.Subscribe(watcher1);

        Console.WriteLine(new string('-', 30));
        tcs.Price = 3200;
        infy.Price = 1070;

        Console.Read();
    }
}

Output –


As per this example, the client class creates multiple subjects (stocks) and watchers (subscribers). The client class is also responsible for subscribe and unsubscribe watchers to particular subject (stock). After successful registration, whenever subject’s state (stock price) changes, the respective subscribers will get notify about change.

You can download full code from Gist.

I hope this article helps you to know more about Observer Design Pattern. Please leave your feedback in comments section below.

References –
DoFactory

See Also –
Memento Pattern
Mediator Pattern
Iterator Pattern

No comments:

Post a Comment