LasaterConsulting.com

Design Patterns
Type-Object | Properties | Strategy | Entity Relationship | Interpreter | Project Usage | AOM UI

Mediator Pattern

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 mind set, 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, this 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 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 a 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 we see the WorkerObject again in this example, but it is slightly different. It contains this time 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 cumbersomeif...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)
					{
						//send message to all other objects registered
						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 just be redoing the if...then...else statement in a different manner. What does this buy us? Well lets 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 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 might stress that making the effort to use patterns will strengthen your overall design ability, but like your basic coding skills, it is something learned 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.

Related Articles

Other articles in this series include:

  1. Bridge & Adapter Pattern
  2. Chain Of Responsibility Pattern
  3. Facade Pattern
  4. Factory & Strategy Pattern
  5. Mediator Pattern
| Make a Donation to Help Build/Maintain our site! |©2004 Lasater Consulting

1