Learn the Observer Pattern:
I am starting to write a series of blog post which would be named “Learn {tagline}…..”
In these series I would post things about design pattern, programming methodologies, skills etc etc
For today, I will start with my favorite Design Pattern. The Observer Pattern.
I would first state out what the GoF book, states as the intent of this pattern.
Intent
- Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Applicability of this pattern
- When a change to one object requires changing others, and you don’t know how many objects need to be changed
- When an object should be able to notify other objects without making assumptions about who these objects are. (Loosely coupled objects)
- When an abstraction has two aspects, one dependent on the other.
UML Structure
Sample Code
I am going to write a sample application using WPF to show how to use the pattern. One may say its an overkill but it does show loose coupling.
First our pattern, our class diagram would look like this
Our Interface ISubject and our Concrete Subject implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
namespace ObserverPattern { public interface ISubject { void Add(IObserverable o); void Remove(IObserverable o); void Notify(); string GetState(); void SetState(string state); } public class Subject : ISubject { private readonly IList<IObserverable> _list = new List<IObserverable>(); private string _state = string.Empty; public void Add(IObserverable o) { if(!_list.Contains(o)) _list.Add(o); } public void Remove(IObserverable o) { if (_list.Contains(o)) _list.Remove(o); } public void Notify() { foreach (var observerable in _list) { observerable.Update(); } } public string GetState() { return _state; } public void SetState(string state) { _state = state; Notify(); } } } |
Next the interface for IObserver
1 2 3 4 5 6 7 |
namespace ObserverPattern { public interface IObserver { void Update(); } } |
Now that we got the pattern in place, let start with creating two UserControl in WPF, we will create an English and Turkish Label Control that implements the IObserver interface, as shown in the class diagram below
English and Turkish Label Control implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
using System.Windows.Controls; using ObserverPattern; namespace ObserverPatternWPFApp { /// <summary> /// Interaction logic for LabelEnglishControlObserver.xaml /// </summary> public partial class LabelEnglishControlObserver : UserControl, IObserver { public LabelEnglishControlObserver(ISubject subject) { OurSubject = subject; InitializeComponent(); } public LabelEnglishControlObserver() { InitializeComponent(); } public ISubject OurSubject { get; set; } public void Update() { if(OurSubject != null) label1.Content = OurSubject.GetState(); } } /// <summary> /// Interaction logic for LabelTurkishControlObserver.xaml /// </summary> public partial class LabelTurkishControlObserver : UserControl, IObserver { private ISubject _subject; private IDictionary<string,string> _dict = new Dictionary<string, string>(); public LabelTurkishControlObserver() { InitializeComponent(); InitDict(); } public LabelTurkishControlObserver(ISubject subject) { OurSubject = subject; InitializeComponent(); InitDict(); } private void InitDict() { _dict.Add("Hello", "Merhaba"); _dict.Add("World", "Dünya"); _dict.Add("Goodbye", "Güle Güle"); _dict.Add("Cat", "Kedi"); _dict.Add("Dog", "Köpek"); _dict.Add("Apple", "Elma"); _dict.Add("Man", "Adam"); _dict.Add("Women", "Kadin"); } public ISubject OurSubject { get; set; } public void Update() { if(OurSubject != null) label1.Content = _dict.ContainsKey(OurSubject.GetState()) ? _dict[OurSubject.GetState()] : "Cannot find it in turkish"; } } } |
Simple nothing fancy about these 2 controls other than the Turkish one, which has English -> Turkish hard coded translation.
Now lets see how the WPF app looks like and how it hooks it all up.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
using ObserverPattern; namespace ObserverPatternWPFApp { /// <summary> /// Interaction logic for ObserverWindow.xaml /// </summary> public partial class ObserverWindow : Window { private Subject subject = new Subject(); private IList<string> _state = new List<string>(); public ObserverWindow() { InitializeComponent(); subject.Add(EnglishLabel); subject.Add(TurkishLabel); EnglishLabel.OurSubject = subject; TurkishLabel.OurSubject = subject; _state.Add("Hello"); _state.Add("World"); _state.Add("Goodbye"); _state.Add("Cat"); _state.Add("Dog"); _state.Add("Apple"); _state.Add("Man"); _state.Add("Women"); _state.Add("Groovy"); } private void button1_Click(object sender, RoutedEventArgs e) { var random = new Random(); var i = random.Next(_state.Count); subject.SetState(_state[i]); } } } |
Application Screen shot
Conclusion
Our main WPF app hooks the EnglishControl and TurkishControl with the Concrete Subject by using poor man’s Property Injection in the Default Constructor of the App. When a button is clicked on the App it sets the Subject State to a random English word from the list. This in turns calls the Notify on the Subject and it will then notify all its IObservers.
Additionally I would like to mention that we have used the pull method. Where we request to get the state from the subject, we could also use the push method where the subject will sends details information about the change to the observer. The push method makes the observer less reusable, because Subject class makes assumptions about the Observer classes that might not always be true. I suggest one to use the pull method whenever possible.
Once you understand the Observer Pattern concept, it is very easy to implement your own Events, the basic idea of Events is the Observer Pattern. In my next post I will show you how to use Events and Delegates to implement Observer Pattern in C#
You can also download the entire source code.
Hope you enjoy the first series of the Learn topics, will be posting more in the future.