Introduction
Developers in .NET sometimes come from scripting language environments that are not strong on Object Oriented methodologies. OO methodologies like Refactoring and using design patterns can be intimidating and the value for the developer is hard to see. What developers new to the OO world, and even more seasoned developers, need to understand is that good design is not beyond scope in any project. Good habits simply must be learned that will make the developer a better designer.
In that mindset, I am submitting the first of several "how to" real world examples, used in my professional life, on how to use patterns in a simple, easy to follow manner. Many of us have ended up either writing or working on in-line, scripting based code. Taking some ideologies from refactoring methodology, is not necessarily a bad thing. Of course, when you are first writing an algorithm or a series of logic statements, it seems easier to start with if....then....else
. But as you continue to expand this code to more complex forms, this model can quickly become unmanageable. This is where refactoring and design pattern methodology can play an important and useful part in simplifying, enhancing and making the code more useable (and understandable) to those who practice good OO design.
This article details a real world example of how to use the mediator pattern to help you develop a method to communicate between several classes. The mediator pattern is used when mediation is needed between several classes, to communicate in an indirect manner.
Background
I have used mediators in several different ways throughout my professional career, but the cleanest way to recognize a mediator pattern is any class that facilitates indirect communication between a series of other classes. This example is fairly light in inheritance, simply because I did not want to add too much into the conversion between if...then...else
code and the pattern, thus potentially confusing the developer on the minimum requirements of the mediator pattern.
How to use the code
The first thing we should note is the WorkerObject
in this example. It contains a constructor that accepts a string
parameter, a two way accessor and a method SendMessage
:
public class WorkerObject
{
private string _message;
public WorkerObject(string message)
{
_message = message;
}
public string Message
{
get{return _message;}
set{_message = value;
}
public SendMessage(string message)
{
Console.WriteLine("Message sent : " + message);
}
}
Next we see the functional code, as it exists at the beginning of the refactoring effort. Notice the class construction declarations, each passing in a slightly different string
variable, and behind that, the if...then...else
statement, which checks the Message
accessor of the sender object and based on that value not being the same as the sender object, performs the SendMessage
method on the appropriate object:
WorkerObject senderObject = new WorkerObject("message0");
WorkerObject workerObject1 = new WorkerObject("message1");
WorkerObject workerObject2 = new WorkerObject("message2");
WorkerObject workerObject3 = new WorkerObject("message3");
if(!workerObject1.Message.Equals(senderObject.Message)
{
workerObject1.SendMessage(senderObject.Message);
}
if(!workerObject2.Message.Equals(senderObject.Message)
{
workerObject2.SendMessage(senderObject.Message);
}
if(!workerObject3.Message.Equals(senderObject.Message)
{
workerObject3.SendMessage(senderObject.Message);
}
Now to move this code from the overly cumbersome if...then...else
statements, we create a mediator class, DoSomeMediation
. This class contains two methods Register
and SendMessage
. The Register
method catalogs all the classes we want to mediate between. The SendMessage
method is where the functional code actually exists, and calls all the registered objects, ignoring the passed in object if it exists in the mediator class, and calls the SendMessage
method on each class, passing in the passed objects Message
accessor:
public class DoSomeMediation
{
private static ArrayList _workerObjects = new ArrayList();
public static int Register(WorkerObject workerObject)
{
return _workerObjects.Add(workerObject);
}
public static void SendMessage(WorkerObject senderObject)
{
if(senderObject == null) return;
string messageToSend = senderObject.Message;
foreach(WorkerObject workerObject in _workerObjects)
{
if(!workerObject.Message.Equals(senderObject.Message))
workerObject.SendMessage(messageToSend);
}
}
}
Next we see the execution code. Notice that while we still construct the WorkerObject
objects the same way, now instead of the if...then...else
code making the determination of which objects to call the SendMessage
method on, we let the mediator class handle the communication between the classes.
WorkerObject senderObject = new WorkerObject("message0");
WorkerObject workerObject1 = new WorkerObject("message1");
WorkerObject workerObject2 = new WorkerObject("message2");
WorkerObject workerObject3 = new WorkerObject("message3");
DoSomeMediation.Register(senderObject);
DoSomeMediation.Register(workerObject1);
DoSomeMediation.Register(workerObject2);
DoSomeMediation.Register(workerObject3);
DoSomeMediation.SendMessage(senderObject);
Points of interest
This particular example seems to be redoing the if...then...else
statement in a different manner. What does this buy us? Well let's say we wanted to pass into the executed code a collection of WorkerObject
objects, instead of the manual construction. Using the if...then...else
code we could not make a runtime change to the number or type of objects that could communicate between each other.
This is the third installment in the series I am writing on real world design patterns. All examples and the bulk of this article are taken from my professional experience as an architect. The examples given are templates only, and the designer must keep in mind that they are the ones who must decide where different patterns, if any, may be best used in their code.
Deciding to perform a refactoring effort from the existing code to a pattern must be weighed on the necessity and need of the code itself. Patterns are only design templates, helpers to accommodate better overall design. I must stress that making an effort to use the patterns will strengthen your overall design ability, but like your basic coding skills, it is something that is to be learnt and cultivated.
If this or any other in this series on design patterns is helpful or you have questions or comments please e-mail me at chris.lasater@gmail.com.
History
This is the first revision and is the third installment in a series.