-->

16/01/2012

Behavioral Patterns - Observer Pattern

Lets not follow the text book definition of Observer Pattern.
Start with OO Principles.
OO Principle says, "Strive for loosely coupled design between objects that Interact".
Loose coupling brings the flexibility and resilience in system.

Lets take Facebook notifications as an example.
When there is any changes in my profile or wall , it will be automatically notified to my friends.
In this case, i am the subject and My friends are Observers. My friends list may vary. People may be added or removed from the list. But the system should be flexible enough to communicate the information despite of the change in observers list.


Observer Pattern : Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
  
Objective: Demonstrate Observer Pattern using Blog Notifications.
When people Join or Subscribe a Blog or Community, it will send the notifications automatically in case of any changes.As they are loosely coupled, changes in one shouldn't effect other.
Lets see How.

Step 1: Create an Interface for both IBlog and IObserver.
//Interface for Blog.
namespace ObserverSample
{
    public interface IBlog
    {
        List Posts { get; }
        void RegisterObserver(IObserver observer);
        void UnRegisterObserver(IObserver observer);        
        void AddNewPostToBlog(string strPost);
        void InformObservers();
    }
}
//Interface for Observer.
namespace ObserverSample
{
    public interface IObserver
    {
        string _CommonKey { get; }
        void GetLatestPostDetails(IBlog _blog);
    }
}
Step 2: I created two types of Observers. Mail Subscribers and Mobile Subscribers.
//Mail Observers.
namespace ObserverSample
{
    public class MailObserver:IObserver
    {
        public string _mailId;

        public MailObserver(string mailId)
        {
            _mailId = mailId;
        }
        public void GetLatestPostDetails(IBlog _blog)
        {
            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("*********** Start of Mail Notification ****************");
            Console.WriteLine("Got Update from " + _blog.GetType().Name + " to " + _mailId);
            Console.WriteLine("List of Posts:");
            Console.WriteLine("-------------");
            foreach (string _post in _blog.Posts)
            {
                Console.WriteLine(_post);
            }
            Console.WriteLine("************* End of Mail Notification ******************");
        }

        public string _CommonKey
        {
            get
            { return _mailId; }            
        }
    }
}
//Mobile Observers.
namespace ObserverSample
{
    public class MobileObserver:IObserver
    {
        public string _mobileNo;

        public MobileObserver(string mobileNo)
        {
            _mobileNo = mobileNo;
        }
        public void GetLatestPostDetails(IBlog _blog)
        {
            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("*********** Start of Mobile Notification ****************");
            Console.WriteLine("Got Update from " + _blog.GetType().Name + " to Mobile: " + _mobileNo);
            Console.WriteLine("List of Posts:");
            Console.WriteLine("-------------");
            foreach (string _post in _blog.Posts)
            {
                Console.WriteLine(_post);
            }
            Console.WriteLine("************* End of Mobile Notification ******************");
        }

        public string _CommonKey
        {
            get { return _mobileNo; }
        }
    }
}
Step 3: I created a class "PratapBlog" implementing IBlog.
namespace ObserverSample
{
    public class PratapBlog: IBlog    
    {
        private List _Observers = new List();
        private List _mailObservers = new List();
        private List _mobileObservers = new List();
        private List _posts = new List { "Pratap Blog Post1", "Pratap Blog Post2" };

        public void RegisterObserver(IObserver _observer)
        {   
                Console.WriteLine(Environment.NewLine);
                Console.WriteLine("*********** Start of Registration ****************");                
                _Observers.Add(_observer);
                Console.WriteLine("Registering Observer Type: "+_observer.GetType().Name+"; Observer: " + _observer._CommonKey);    
                Console.WriteLine("*********** End of Registration ****************");            
            
        }

        public void UnRegisterObserver(IObserver _observer)
        {
            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("*********** Start of UnRegistration ****************");
            Console.WriteLine("UnRegistering Observer Type: " + _observer.GetType().Name + "; Observer: " + _observer._CommonKey);
            _Observers.Remove(_observer);            
            Console.WriteLine("*********** End of UnRegistration ****************");
        }

        public void AddNewPostToBlog(string _strPost)
        {
            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("Adding New post to Pratap Blog : " + _strPost);
            _posts.Add(_strPost);
            InformObservers();
        }

        public void InformObservers()
        {
            foreach (IObserver _observer in _Observers)
            {
                _observer.GetLatestPostDetails(this);
            }            
        }
        public List Posts
        {
            get
            {   return _posts;    }            
        }
    }
}
Now, before going to actual program, lets see what we have implemented.
1. The only thing our Blog (Subject) knows is that all the Observers implement IObserver interface.
2. So it doesn't need to know the concrete implementation of IObserver Interface.
3. Blog(Subject) will send notifications to any Observer Implemented IObserver and registered with it.
4. Blog(Subject) will stop sending Notifications to unregistered Observers.

Step 4: Now create respective Objects for Blog and Observers and test different scenarios.

Step 5: As a first test, i will create 1 Mail Subscriber and 2 Mobile Subscribers and try to add a new posting to my blog. When this is done, my blog should send the notification to all the observers.
Code Written in Program:
PratapBlog _pratapBlog = new PratapBlog();
IObserver _FirstMailObserver = new MailObserver("FirstMail@domain.com");
IObserver _FirstMobileObserver = new MobileObserver("FirstMobileNo");
IObserver _SecondMobileObserver = new MobileObserver("SecondMobileNo");
Console.WriteLine(Environment.NewLine);
Console.WriteLine("*********** First Part **************");
//Above created 1 Mail Observer and 2 Mobile Observer are registered with Pratap Blog.            
_pratapBlog.RegisterObserver(_FirstMailObserver);
_pratapBlog.RegisterObserver(_FirstMobileObserver);
_pratapBlog.RegisterObserver(_SecondMobileObserver);
//A new post is added to Blog, so as per our code Blog (Subject) will notify all the Observers Registered.
_pratapBlog.AddNewPostToBlog("Pratap Blog Post3");
Now lets see what is the Output:

Step 6: Now after doing what we have done in earlier step now, i will try to Unregister first Mobile observer and try to add another post to Pratap Blog.
This time, Blog (Subject) shouldn't send any notifications to Unregistered Observer.
After adding Part 2 statements, Program code will look like this.
PratapBlog _pratapBlog = new PratapBlog();
IObserver _FirstMailObserver = new MailObserver("FirstMail@domain.com");
IObserver _FirstMobileObserver = new MobileObserver("FirstMobileNo");
IObserver _SecondMobileObserver = new MobileObserver("SecondMobileNo");
Console.WriteLine(Environment.NewLine);
Console.WriteLine("*********** First Part **************");
//Above created 1 Mail Observer and 2 Mobile Observer are registered with Pratap Blog.            
_pratapBlog.RegisterObserver(_FirstMailObserver);
_pratapBlog.RegisterObserver(_FirstMobileObserver);
_pratapBlog.RegisterObserver(_SecondMobileObserver);
//A new post is added to Blog, so as per our code, Blog (Subject) will notify all the Observers Registered.
_pratapBlog.AddNewPostToBlog("Pratap Blog Post3");
//Second Part starts here.
Console.WriteLine("*********** Second Part **************");
//UnRegistering First Mobile Observer.
_pratapBlog.UnRegisterObserver(_FirstMobileObserver);
//A new post is added to Blog, so as per our code, Blog (Subject) shouldn't send any Notifications to Unregistered Observer.
_pratapBlog.AddNewPostToBlog("Pratap Blog Post4");
Now lets see what is the Output:

Now you can see, once an observer got unregistered, no notifications were send to it.


Summary: Observer Pattern has been implemented with loose coupling between Subject and Observers.
Even if we have a new type of Observer in future, say FaxObserver, No code changes has to be done in PratapBlog class. All it has to do is implement IObserver interface and get registered with PratapBlog (Subject).

Is it helpful for you? Kindly let me know your comments / Questions.

4 comments:

  1. Very good explanation. Looking forward to see more topics like this. Thank you
    Gopal

    ReplyDelete
  2. I have read a lot of articles you have written and posted here. All are very understandable and useful.
    Thank you.

    George

    ReplyDelete
  3. Neat blog! Is your theme custom made or did you download it from somewhere?
    A design like yours with a few simple tweeks would really make my blog
    shine. Please let me know where you got your theme.

    With thanks
    Here is my web site ; zunehmend

    ReplyDelete