Click here to Skip to main content
Click here to Skip to main content

Implement Observer Pattern in an Absolutely Easy Example

By , 16 Sep 2008
 
pic11.JPG

Introduction

When you develop your application, I'm sure that you have to handle several objects.
If they have to interact with the same source data, I think that you must find a way to update them with the change of data. Observer pattern is the key you can use for this solution!

Background

I have searched this website and found a few articles about the Observer pattern. And I have read some articles about event and delegate too. I want to show you - the new developers - the way to implement Observer pattern in the easiest, fastest way that is easiest to understand.

Now, let's start!

Using the Code

I created an example in Winforms, using C# language in .NET Framework 2.0.

  • I have 2 forms: Form2 and Form3
  • In form2, there are 3 radio buttons, a Label and a Button. If you check the radio button, you'll see that the forecolor of label will change with the color is the name of that radio button. It's very easy, isn't it?
  • When you click on button to open child form, Form3 will show! If you check the radio button again, beside the forecolor of label change, you'll see that the backcolor of textbox in Form3 will be changed too! That's it!
  • I have 2 objects in this solution:
    • Subject: It will be the parent! When a client is created, the client must be registered with this subject. When something changes, the subject will notify all the clients it manages to update them.
    • Observer: It's a client. When it is born, it will have to register with subject and wait to update if there's some change.

Subject Object

First, I create a delegate and an event to make it "alive" when something changes!

private delegate void NotifyHandler(string _color);
private event NotifyHandler NotifyEvent;  

I also create ArrayList names arrObs to manage all client objects when it registers to Subject object.

ArrayList arrObs = new ArrayList();

The full details of the subject are here:

public class Subject
{
   ArrayList arrObs = new ArrayList();
   private delegate void NotifyHandler(string _color);
   private event NotifyHandler NotifyEvent;

   public Subject()
   {
      this.NotifyEvent += new NotifyHandler(Notify);
   }

   public void UpdateClient(string _color)
   {
       OnNotify(_color);
   }

   private void OnNotify(string _color)
   {
       if (NotifyEvent != null)
       {
           NotifyEvent(_color);
       }
   }

   private void Notify(string _color)
   {
       for (int i = 0; i < arrObs.Count; i++)
       {
           Observer obs = (Observer)arrObs[i];
           obs.Update(_color);
       }
   }

   public void RegisterClient(Observer obs)
   {
       arrObs.Add(obs);
   }
}

You will see that when the subject is created, it will register the NotifyEvent with Notify method. In Notify(), it passes the _color string to all the clients in arrObs. And clients will call Update method to update the color.

Now, let's see the client object names Observer!

Observer Object

Same as Subject object, I will define a delegate and an event to make it alive when subject notifies them!

private delegate void ColorEventHandler(string _color);
private event ColorEventHandler ColorChangedEvent;  

Like the subject, when subject notifies to observer (in Update method above), the ColorChangedEvent will be fired and call ColorEventHander to pass the _color string to update!

In this solution, I want to update the back color of Form3. So, this observer object will be created in form3 and pass the textbox object to observer in constructor:

private TextBox txt;
public Observer(TextBox _txt)
{
     this.ColorChangedEvent += new ColorEventHandler(Observer_ColorChangedEvent);
     this.txt = _txt;
}  

The full details of Observer object will be here:

public class Observer
{
    private delegate void ColorEventHandler(string _color);
    private event ColorEventHandler ColorChangedEvent;
    private TextBox txt;

    public Observer(TextBox _txt)
    {
        this.ColorChangedEvent += new ColorEventHandler(Observer_ColorChangedEvent);
        this.txt = _txt;
    }

    private void OnChange(string _color)
    {
        if (ColorChangedEvent != null)
        {
            ColorChangedEvent(_color);
        }
    }

    public void Update(string _color)
    {
        OnChange(_color);
    }

    private void Observer_ColorChangedEvent(string _color)
    {
        switch (_color)
        {
            case "RED":
                txt.BackColor = Color.Red;
                break;
            case "BLUE":
                txt.BackColor = Color.Blue;
                break;
            case "GREEN":
                txt.BackColor = Color.Green;
                break;
            default:
                txt.BackColor = Color.Gray;
                break;
        }
    }
}

Form2

When radio button is checked, it changed! It will call the Subject object to update its client.

private void rdRed_CheckedChanged(object sender, EventArgs e)
{
      if (rdRed.Checked)
      {
          objSub.UpdateClient("RED");
          lblText.ForeColor = Color.Red;
      }
 }

 private void rdGreen_CheckedChanged(object sender, EventArgs e)
 {
       if (rdGreen.Checked)
       {
           objSub.UpdateClient("GREEN");
           lblText.ForeColor = Color.Green;
       }
 }

 private void rdBlue_CheckedChanged(object sender, EventArgs e)
 {
       if (rdBlue.Checked)
       {
           objSub.UpdateClient("BLUE");
           lblText.ForeColor = Color.Blue;
       }
  }

When you click on Button to create and open Form3, there is a subject object name objSub that was created in form and passed to form3 through the constructor:

private Subject objSub;
private Form3 frm;
public Form2()
{
     InitializeComponent();
     objSub = new Subject();
}

private void btnOpen_Click(object sender, EventArgs e)
{
     frm = new Form3(objSub);
     frm.Show();
} 

Form3

Only create a new Observer object and register it with the objSub

public Form3(Subject _objSub)
{
     InitializeComponent();
     objSub = _objSub;
     obs = new Observer(this.textBox1);
     objSub.RegisterClient(obs);
}

That's all! When you click on the radio button, it will call the subject to update clients in its arraylist. The client will be notified and will update the background of textbox with the color passed through by the subject.

Points of Interest

It is compact to implement Observer pattern in an easy example! Hope you can understand and learn how to solve your problem from this small example!

Feel free to contact me!

Name: Nguyen Anh Vu(Mr.)
Email: vuna209@gmail.com
Mobile: +84984886940
Addr: 7 floor, 53 Quang Trung, Hanoi, VietNam.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Ng. Anh Vu
Web Developer
Vietnam Vietnam
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalit works ok with the textbox but not with the listboxmembernipsonanomimata2 Oct '09 - 21:49 
here is the code
 
any thoughts
 
it seems strange..
GeneralRe: it works ok with the textbox but not with the listboxmembernipsonanomimata3 Oct '09 - 0:02 
vs2010 gave me the answer
you have to instantiate the two controls in the class level and everything works fine.
GeneralGood article [modified]memberDonsw21 Jan '09 - 14:50 
Good article one thing I would do to make it better is talk more about the patterns up front for those who either do not know the patterns or have forgotten the patterns. Otherwise this is a good article. Smile | :)
 
modified on Wednesday, January 21, 2009 8:58 PM

Generalvery goodmemberDearMadalin22 Sep '08 - 15:40 
Big Grin | :-D I have learnt something new today
 
Lay down the program and immediately become a Buddha

QuestionWhy so complicated?memberptmcomp22 Sep '08 - 9:19 
.NET's events themselves are an implementation of the Observer Pattern. There is no need to build a second registration and notification algorithm around it.
Patterns can be implemented differently. E.g. "for each" is an implementation of the iterator pattern.
AnswerRe: Why so complicated?memberspiderman_anhvu22 Sep '08 - 17:30 
yeah, of course you can make a similar example with another way! such as you can reference the textbox of Form3 with Form2. But in this example, i want to introduce how to implement observer pattern with event and delegate! Through this example, you can understand about observer pattern, event and delegate. The last question, if you have to do this example in .NET Remoting, How will you do? That's it! I want to say about observer pattern in Remoting using event and delegate Now, do you understand what i want to say about through this example? Big Grin | :-D
 
anyway, thanks for your question!
GeneralRe: Why so complicated?memberfire_birdie22 Sep '08 - 19:49 
WTF | :WTF: My head hurts just from reading that. I agree with ptmcomp, this is far too complicated. I think you should do some more reading on the subject of delegates, the code you are adding doesn't seem to have any real value.
 
Using the += operator creates a multi-cast delegate so there is no need to create an ArrayList. If you use the standard pattern for events in .NET (object sender, EventArgs args) your observers should be given all the info they require.
 
You might want to have a look at System.ComponentModel.INotifyPropertyChanged. Finally, how does your method help with Remoting?
GeneralRe: Why so complicated?memberspiderman_anhvu22 Sep '08 - 21:19 
okie, this example is only for beginner, who want to understand more about event and delegate. I haven't read about System.ComponentModel.INotifyPropertyChanged yet. So if you can, could you show me an example please? thanks a lot!
I think in remoting callback, i could use event and delegate to make server be able to talk to client.
GeneralRe: Why so complicated?memberfire_birdie22 Sep '08 - 21:50 
INotifyPropertyChanged provides a simple event for notifying other objects that a property has changed. It is used in WPF as a form of data binding.
 
using System;
using System.ComponentModel;
 
public class Observable : INotifyPropertyChanged
{
	#region Fields
	private string name;
	#endregion
 
	#region Properties
	public string Name
	{
		get
		{
			return this.name;
		}
 
		set
		{
			// Only fire the event if the value actually changed
			if(this.name != value)
			{
				this.name = value;
				this.OnPropertyChanged("Name");
			}
		}
	}
	#endregion
 
	#region Methods
	protected void OnPropertyChanged(string propertyName)
	{
		// Make a copy of the delegate for thread safety
		PropertyChangedEventHandler temp = this.PropertyChanged;
 
		if(temp != null)
		{
			// Call the delegate if there are any registered observers
			temp(this, new PropertyChangedEventArgs(propertyName));
		}
	}
	#endregion
 
	#region INotifyPropertyChanged Members
	public event PropertyChangedEventHandler PropertyChanged;
	#endregion
}
 
An observer can handle the PropertyChanged event with a switch statement to filter the properties it is interested in and update itself accordingly. It's also possible to derive a class from PropertyChangedEventArgs to include the previous and new value of the property. There is no need for an ArrayList because (as my previous message stated) the delegate will handle that for you.
 
Remoting and delegates should be handled with care. A delegate holds a reference to both the method and the instance it wraps; it needs to be carefully designed when it crosses app domain boundries.
 
And finally, I would recommend beginners read the documentation for delegates before attempting anything like this.
 
cheers

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 16 Sep 2008
Article Copyright 2008 by Ng. Anh Vu
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid