I have recently been studying design patterns in the hope to improve my code not only from a readability standpoint but from a functional perspective as well. I figured the best way to learn something properly is to write about it. So here I go on the Observer Pattern.
I found a simple yet concise definition on data & object factory:
Define a one-to-many dependency between objects so that when one object changes state, all its dependants are notified an updated automatically. [link]
I then took this and thought it was best to come up with an analogy to remember this by more simply. So here I go (Maybe it won’t work, or maybe you have a simpler idea. Please let me know):
Twitter is a good example of this pattern. When you follow someone you are a dependant on that person (and visa versa when someone is following you). When the person being followed updates their status, feed, micro-blog (or whatever name they have for it), then all dependants, ie: those who are following, are also notified of the update and have the opportunity to react to it.
That was as simple as I can get. Basic principle found in every day life really. We could also liken it to a blog that updates its subscribers. From that we need to delve into the parts of the pattern to understand it and write code around the pattern. There are only a few things that need to be remembered.
- Subject (the person being followed).
- Observer (the person following).
As with everything in programming we try and abstract away as much as possible to understand it better and to improve reuse. So there are going to be interfaces and abstract classes in this pattern when used properly (IMHO). Lets start by creating a simple Subject Class which contains a List or ArrayList of Observers.
Subject Class
1: public abstract class Subject {
2: List<IObserver> observers { get; set; }
3: }
This looks a bit bare. Lets flesh it out with the next step. The logical thing is to realise that once we make a tweet we want to be able to notify the follower that we have updated our status. Ok, that’s fine, but there are two other things that we might want to do. We might want to let someone else follow us (attach), or we might want to block someone who is already following us (detach). So we need to add some code to show that is possible.
1: public void Attach() { }
2: public void Detach() { }
3: public void Notify() { }
Super easy. Now we just need to add some simple code to these methods to make them do something.
1: public abstract class Subject {
2: List<IObserver> observers { get; set; }
3: public Subject() {
4: observers = new List<IObserver>();
5: }
6: public void Attach(IObserver observer) {
7: observers.Add(observer);
8: }
9: public void Detach(IObserver observer) {
10: observers.Remove(observer);
11: }
12: public void Notify() {
13: foreach(IObserver observer in observers){
14: observer.Update();
15: }
16: }
17: }
One thing that I am forgetting is the IObserver interface. It is completely simple and contains one method:
1: public interface IObserver {
2: void Update();
3: }
Well, now that we have our abstract Subject class and our IObserver interface we are ready to implement the pattern into something a little more concrete. So let’s go ahead and do that now. Let’s create a simple Concrete Subject class:
1: public class OurSubject<T> : Subject {
2: public T SubjectState { get; set; }
3: }
That is as simple as I can find. Then we move onto implementing the IObserver interface. Lets work with that:
1: public class OurObserver<T> : IObserver {
2: public OurSubject<T> Subject { get; set; }
3: public T _observerState;
4:
5: public OurObserver(OurSubject<T> subject){
6: Subject = subject;
7: }
8: public void Update() {
9: _observerState = Subject.SubjectState;
10: }
11: }
So really all that is happening there is the OurObserver is being updated every time that OurSubject changes state. Lets run the below code (with a small mod) and see what we can see:
1: OurSubject<string> subject = new OurSubject<string>();
2: subject.Attach(new OurObserver<string>(subject));
3: subject.Attach(new OurObserver<string>(subject));
4: subject.SubjectState = "Changing state";
5: subject.Notify();
Our output is as follows:
Where the code at the end is the hashcode of the object. So we can see that it is clearly working right the way that we want it to.
Lets do something a little more along the lines of the analogy that we used before hand. Lets create a Twitterer (subject, poster) and a Twitteree (follower) and see what we can see. Using the abstract Subject class and the IObserver interface we can do the following (it is not very pretty and could be vastly improved):
1: public class Twitterer : Subject {
2: private string _currentTweet;
3: public string CurrentTweet {
4: get { return _currentTweet; }
5: set { _currentTweet = value; Notify(); }
6: }
7: public void Tweet(string tweet) {
8: CurrentTweet = tweet;
9: }
10: }
11:
12: public class Twitteree : IObserver {
13: public Twitterer OurHero { get; set; }
14: public string myName { get; set; }
15: public Twitteree(string name) {
16: this.myName = name;
17: }
18: public void Update() {
19: Console.WriteLine("Twitteree {0} received a tweet", this.myName);
20: }
21: }
Then when we run it we get:
This is the most basic of introductions that I can do and as my understanding increases of design patterns I am sure that more insightful posts will follow.
For reference purposes please see: