As you can see the freighter can no longer call the method FireMissles() , it would cause a compiler error so our bug would be picked up at compile time instead of runtime. However it can but it can GoLightSpeed()!

Thursday, February 25, 2010

The Observer Pattern is an often used design pattern in software development. The idea is one class (the publisher ) publishes an event (say a button click) and other objects can subscribe to that event and do something fancy when they hear about it.

The .NET framework uses delegates and events to follow the Observer pattern.

The example below allows a usercontrol (the publisher) embedded in an aspx page to tell the subscriber, in this case the aspx page when a button has been clicked.

So I can subscribe to the event BubbleClick and tell it that a new event will need to be notified when that event occurs, in this case it is a event called eventRejectRedemptionSubmit_Click in the aspx page.

There are a lot of articles on the internet on how to use delegates in C#. Normally something along the lines of “They are type safe versions of c/c++ function pointers”. This explanation is correct but means nothing if you have no experience in C!

So here is an explanation of why one would use a delegate. (They are used in events too but let’s leave that for now).

Remember one of the key principals in OOP is CHANGE. So things change all the time, the less areas of code we have to change the less likely bugs will appear

Here is the issue without using a delegate

An error occurs in our program and we want to log it somewhere. At the start of the project we have a static class Logger that has one method

public static class Logger

{

public static void WriteLogToDatabase(string textToLog)

{

Console.WriteLine("Writing to database the text " + textToLog);

}

}

From the main program we call the method like

class Program

{

static void Main(string[] args)

{

Logger.WriteLogToDatabase("An error has occured again");

}

}

All well and good we have deployed the project and it works great

We have decided we need to write errors to XML as well. So now you have to change the class Logger (which we know works but will have to be tested again because we have altered it) to include the new method and change main program to call it, now we have:

public static class Logger

{

public static void WriteLogToDatabase(string textToLog)

{

Console.WriteLine("Writing to database the text " + textToLog);

}

public static void WriteLogToXML(string textToLog)

{

Console.WriteLine("Writing to XML the text " + textToLog);

}

}

From the main program we call the method like:

class Program

{

static void Main(string[] args)

{

Logger.WriteLogToDatabase("An error has occured again");

Logger.WriteLogToXML("An error has occured again");

}

}

Now we have only 2 methods and you have to alter the code in 2 places main.cs and Logger.cs. What would happen if you had to add more methods e.g. WriteLogToMobile, WriteLogToPrinter , WriteLogToSomeFutureDeviceThatHasNotBeenInvented, another 50 methods? Changing the code over and over, more bugs, more places to change code.

Now it gets worse, another developer has created some more logging methods in another class that you want to call in your Logger.cs class. Time to change the code yet again, pasting new code into your logger class.

A solution with delegates

What you could do is change your Logger class to contain a method that accepts a delegate as a parameter. So the new method gets a pointer to a method we want to use. So Logger.cs doesn’t care what the method is, as long as it follows the same signature of the delegate. That means Logger.cs never has to be changed, retested or redeployed.