Introduction
The Observer design pattern is a relationship between objects so that when one changes its state, all the others are notified accordingly. In other words, it defines that an object must be able to notify other objects without making assumptions about what these objects are.
Observer design pattern is quite useful when a change to one object requires changing others but, you don't know how many objects need to be changed.
Using Observer Design Pattern in Blog Subscriber Example
In this example, I have used two other behavioral patterns which are Iterator Design Pattern in C# and Facade Design Pattern in C#. The simplest way to understand observer pattern is to look at blogs, which are websites where people write about different topics. Take an example of one blog where so many users have subscribed themselves for any new post. As we all know, bloggers don't always post regularly so it would be great for bloggers to alert all subscribers whenever the blogger posts a new topic.
Blog is a class which deals with the new blog post and also with the blog subscribers.
BlogPost is a class which deals with the posting of a new article.
Subscribers are the users who have subscribed themselves for alerts of new articles.
Facade deals them in a simpler way and gives you operations like PublishSinglePost() or PublishMultiPost(), etc.
Subject class whose instances independently change their state and it notifies to all the subscribers.
Run method loops through all of the Subscribers calling their Update methods to notify them about post. It also contains methods for attaching and detaching functions with event.
Imagine using Iterator Design Pattern in C# we have a list of subscribers as follows:
class Subscriber
{
public string Name { get; set; }
public string Email { get; set; }
public Subscriber(string name, string email)
{
this.Name = name;
this.Email = email;
}
}
class BlogSubscribers : IEnumerable
{
Subscriber[] Arrays = { new Subscriber("user1", firstEmail@gmail.com),
new Subscriber("user2", "2ndEmail@gmail.com") };
public IEnumerator GetEnumerator()
{
foreach (Subscriber element in Arrays)
yield return element;
}
}
For more details related to the above code and Iterator design pattern, read my article on Iterator Design Pattern in C#.
Subject class instances independently change their state and it notifies to all the subscribers. It defines a Dictionary object to store the subscribers name and their callback functions.
public delegate void Callback(String subscriber);
class Subject
{
Dictionary<string, Callback> Notify = new Dictionary<string, Callback>();
BlogSubscribers blogSubscribers = new BlogSubscribers();
public void Attach(string subscriber, Callback Update)
{
if (!Notify.ContainsKey(subscriber))
{
Notify[subscriber] = delegate { };
}
Notify[subscriber] += Update;
}
public void Detach(string subscriber, Callback Update)
{
Notify[subscriber] -= Update;
}
public void Run()
{
foreach (Subscriber subscriber in blogSubscribers)
{
string message = string.Format(" To {0}<{1}> ",
subscriber.Name, subscriber.Email);
Notify[subscriber.Name](message);
}
}
}
An interface for IObserver specifies how they should be updated. A BlogSpot for posting new articles and observers as a BlogObserver:
interface IObserver
{
void Update(string message);
}
class BlogPost
{
public string PostName { get; set; }
}
class BlogObserver : IObserver
{
Subject subject;
List<BlogPost> ListOfBlogNewPosts = new List<BlogPost>();
public BlogObserver(Subject subject)
{
this.subject = subject;
subject.Attach("user1", Update);
subject.Attach("user2", Update);
}
public void AddPost(BlogPost blogPost)
{
ListOfBlogNewPosts.Add(blogPost);
}
public void Update(string message)
{
foreach (BlogPost blogPost in ListOfBlogNewPosts)
{
Console.WriteLine
("--------------------- New Posting ---------------------");
Console.WriteLine(" {0} for Post {1}", message, blogPost.PostName);
Console.WriteLine();
}
}
public void DetachFromPost(string subscriber)
{
subject.Detach(subscriber, Update);
}
}
I have used Facade Design Pattern in C# to make an easy interface for these different sub systems.
public class BlogFacade
{
public static void PublishMultiPost()
{
Subject subject = new Subject();
BlogPost Ps3 = new BlogPost();
Ps3.PostName = "PS3";
BlogPost Xbox = new BlogPost();
Xbox.PostName = "Xbox";
BlogObserver salmanBlog = new BlogObserver(subject);
salmanBlog.AddPost(Ps3);
salmanBlog.AddPost(Xbox);
subject.Run();
}
public static void PublishSinglePost()
{
Subject subject = new Subject();
BlogPost Xbox = new BlogPost();
Xbox.PostName = "Xbox";
BlogObserver salmanBlog = new BlogObserver(subject);
salmanBlog.AddPost(Xbox);
subject.Run();
}
}
For more details regarding facade pattern, visit Facade Design Pattern in C#.
static void Main()
{
BlogFacade.PublishMultiPost();
}
Output
So if you run facade operation BlogFacade.PublishMultiPost(); by commenting //salmanBlog.DetachFromPost("user2"); then output will be:
and if you uncomment this salmanBlog.DetachFromPost("user2"); and run BlogFacade.PublishMultiPost(); the output will be:
because we have unsubscribed user2 from the list. So that is our blog on Observer pattern if for any new post or change in post, all the others are notified accordingly.
Your feedback is welcome.
View this article on my blog.
CodeProject