Observer Design Pattern in C#
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 likePublishSinglePost()
orPublishMultiPost()
, etc.Subject
class whose instances independently change their state and it notifies to all the subscribers.Run
method loops through all of theSubscribers
calling theirUpdate
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 aDictionary
object to store the subscribers name and their callback functions.public delegate void Callback(String subscriber);
class Subject
{
//Declaring delegate
Dictionary<string, Callback> Notify = new Dictionary<string, Callback>();
//Declaring Event
// List of Users as IEnumerable
BlogSubscribers blogSubscribers = new BlogSubscribers();
/// <summary>
/// Attaching the events
/// </summary>
/// <param name="subscriber">its the name of user or email address</param>
/// <param name="Update">A method to attach </param>
public void Attach(string subscriber, Callback Update)
{
if (!Notify.ContainsKey(subscriber))
{
Notify[subscriber] = delegate { };
}
Notify[subscriber] += Update;
}
/// <summary>
/// To Detach method for specific user
/// </summary>
/// <param name="subscriber">its the name of user or email address</param>
/// <param name="Update">A method to attach</param>
public void Detach(string subscriber, Callback Update)
{
Notify[subscriber] -= Update;
}
/// <summary>
/// Loop through all users to notify for anychange
/// </summary>
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
{
//name of the posting
// Implementing through IOC Inversion of control
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);
//let's try to detach users2 from the subscriber list for posting xbox
//salmanBlog.DetachFromPost("user2");
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.PublishSinglePost();
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 runBlogFacade.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.
0 comments:
Post a Comment