By paddloPayday loans

Home > ActionScript, Design Patterns, Flash, Flex, Mediator, OOP > The Mediator Design Pattern: A Minimalist Example

The Mediator Design Pattern: A Minimalist Example

The Mediator design pattern is easy to understand but tricky to implement. At the core of the Mediator pattern is a Mediator class that coordinates a set of different requests that are sent by objects. The objects are called Colleagues. The Colleagues let the Mediator know that they want to change, and the Mediator handles the change taking into account what effect the changes will have on the other colleagues. For example, in my car when I turn on the headlights, the panel lights dim. Something in my car tells the panel lights to dim when the headlights are switched on. The headlights represent one colleague and the panel lights, another. A Mediator tells the panel lights to turn on as soon as I start the car, and then when the headlights are switched on, the Mediator tells the panel lights to dim. If I turn off the headlight, the Mediator tells the panel lights to brighten up again. The colleagues never communicate directly with one another but instead through the mediator. The idea is to reduce the complexity by handling all of the requests in one place. This also insures loose coupling between the colleagues.

Put succinctly, the Mediator defines an object that encapsulates how a set of objects interacts. (GoF, 273). At the bottom of justifying such an encapsulation is the fact that a loosely coupled design often has many of the objects communicating with one another. The more loosely coupled, the greater the need to communicate. This can get messy if every object is telling every other object its current state and requesting them to adjust to whatever state they are entering. This would be like my headlights communicating directly with my panel lights letting them know whether they are on or off so that the panel lights can make the necessary adjustment. Add other “interested” objects, and pretty soon you have a rat’s nest to coordinate. In order to solve this dilemma, make a cleaner design and ease the interaction, the Mediator is introduced. (Before starting the project, you might want to download the files by clicking the Download button.)

download

The Mediator’s Structure
To get started, the GoF present both a class and interactive diagram and we’ll do the same here in Figure 1:

mediatordiagram

Figure 1: Mediator Class and Interaction Diagrams

As the class diagram shows, two abstract classes, the Mediator and Colleague, each have concrete subclasses. However, a better view can be seen in the interaction diagram. You have a single concrete Mediator handling the interaction between several colleagues. In some cases, the interaction is one way and in others, two-way, but the Colleague instance always has an object reference to the Mediator. The Mediator may or may not have an object reference to the concrete colleague.

Building a Mediator with ActionScript 3.0

In discussing the Mediator design, the GoF note that you really don’t need a Mediator interface since there’s only a single concrete Mediator. However, they go on to suggest that you may have a use case where you may need multiple Mediators; so I elected to leave the abstract Mediator class in the design with the idea that it’s better to have the option of multiple concrete mediators than not.

Next, they point out that while they didn’t do so in their example, you could use an Observer design pattern. This could be done with the Mediator acting as the Observer and the Colleagues as Subjects (See ActionScript 3.0 Design Patterns Ch 8, pg. 282 for a discussion of the Observer design pattern.). Figure 2 shows a way to look at the Observer so that it reveals the Mediator relationships:

ObMediator
Figure 2: Mediator and Observer Class Diagrams

By making a few diagrammatic changes to the Observer pattern you can better see the Mediator. (This helps if you’re familiar with the Observer pattern. However, if you’re not, then treat the rest of this article as new material.) The idea is that the Colleague classes send messages to the Mediator whenever they change state. At this point, the Mediator goes into action and makes the necessary changes to the object that sent the request (to change) as well as any others that need changing. The colleague objects have no communication with one another but allow all requests for change to be handled by the Mediator.

Of course, the big difference is that the Concrete Mediator class is the workhorse of the design. Instead of merely sending out observed behaviors, the Concrete Mediator contains the algorithms that coordinate the different interrelated states. Like the Strategy and State patterns have similar class diagrams, the Observer and Mediator are wholly different in intent and function.

A Minimalist Application

The example to get started on the Mediator is minimalist but it shows the intent of the Mediator clearly and how the different components work together. Originally, I had used an interface instead of an abstract class, but decided to go with the abstract class because it seemed to be more in spirit with the design. First, the two abstract classes are very simple containing only functions for communicating. The first listing is the interface for the Mediator.

Mediator Abstract Class
The Mediator’s abstract class has a single method for updating a concrete colleague’s state.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
package
{
	//Mediator Abstract class
	public class Mediator
	{
		public function update(light:String,col:String):void {};
	}
}

The update() function has parameters for identifying the change and the author (colleague) of the change. The colleague is identified by a string ID. Given the nature of the Mediator, the name can be far more flexible and descriptive using a string rather than the Colleague instance. By using a string, the same colleague structure can be used for several different projects simply by using different string names in the same structure. The only changes would be the names of the identifiers in the concrete mediator and what is passed in the change request.

Colleague Class
The Colleague must both inform the Mediator of the change it wants and listen to the Mediator. The doChange() method passes the change and the colleague name. Rather than having a mediator instance as the parameter for the concrete colleague, this strategy includes the mediator as a parameter of one of its methods.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
package
{
	//Colleague Abstract class
	public class Colleague
	{
		public function listenMediator(m:Mediator):void {}
		public function doChange(light:String,cname:String):void {}
	}
}

This interface is very simple and flexible as is the Mediator interface.

Concrete Mediator Class
This is the heart of the Mediator. It has but a single method (update()), but this method does all the work.

?View Code ACTIONSCRIPT
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
package
{
	//Concrete Mediator
	public class ConcreteMediator extends Mediator
	{
		private var light:String;
		private var lightState:String;
		private var backlightState:String;
 
		function ConcreteMediator()
		{
			trace("Concrete Mediator: Coordinates Colleague Actions");
		}
		public override function update(light:String,c:String):void
		{
			this.light=light;
			switch (c)
			{
				case "col1" :
					if (light=="on")
					{
						lightState="Bright";
					}
					else
					{
						lightState="Dark";
					}
					trace("Headlights are "+lightState);
					break;
 
				case "col2" :
					if (light=="on"&&lightState=="Bright")
					{
						backlightState="Dim light";
					}
					else if (light=="on" && lightState=="Dark")
					{
						backlightState="High light";
					}
					else
					{
						backlightState="No backlight";
					}
					trace("Console lights are "+ backlightState);
					break;
			}
		}
	}
}

As some of you may remember, last year I went on a rant about using conditional statements, and yet here you find a multiple level conditional. The update() function is a switch statement with cases going through a series of if..else statements. This kind of algorithm makes me uncomfortable, and I really would like to modify the concrete mediator class to include some kind of State design. However, that’s not the design, and the other mediator designs I’ve seen don’t spend much time on working out the issues of multiple effects. So, this will have to do for now and as always, we welcome more eloquent solutions.

Concrete Colleague Classes
The two colleague classes are fairly simple as well. They implement the two abstract methods. Because the structure is similar to that of an Observer design pattern, you may be wondering where the array is that pushes each colleague into an array. Instead of using an array, the design incorporates an object. Because there’s only one mediator and there’s no need to inform all of the other colleagues, a simple connection through an object suffices. Also, subscription is not an option here because every class not a mediator is a colleague. In more sophisticated Mediator designs, a Colleague class working almost exactly like a Subject class in an observer structure could be used. Such a design could give each colleague an option to subscribe or not. Here, the design provides no such option and every colleague holds a reference to the mediator.

?View Code ACTIONSCRIPT
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
//Colleague #1
package
{
	public class ConcreteColleague1 extends Colleague
	{
		private var light:String;
		private var colObj:Object;
		private var om:Mediator;
 
		function ConcreteColleague1()
		{
			trace("__Concrete Colleague #1");
			colObj=new Object();
		}
		public override function listenMediator(m:Mediator):void
		{
			colObj.om=m;
		}
 
		public override function doChange(light:String,cn:String):void
		{
			this.light=light;
			colObj.om.update(light,cn)
		}
	}
}
 
//Colleague #2
package
{
	public class ConcreteColleague2 extends Colleague
	{
		private var light:String;
		private var colObj:Object;
		private var om:Mediator;
 
		function ConcreteColleague2()
		{
			trace("__Concrete Colleague #2");
			colObj=new Object  ();
		}
 
		public override function listenMediator(m:Mediator):void
		{
			colObj.om=m;
		}
 
		public override function doChange(light:String,cn:String):void
		{
			this.light=light;
			colObj.om.update(light,cn);
		}
	}
}

In both of the Colleague components, you can see that they change the value of a string named light and provide a colleague name cn that is updated in the Mediator.

Testing the Mediator
To test the mediator all I need are two instances, one each of Colleague1 and Colleague2. One will be changing the state of the headlights and the other changing the state of the panel lights. When the headlights turn on, they impact the state of the panel lights, but the state of the panel lights have no effect on the headlights. However, the colleague instances don’t have to worry about it; the mediator takes care of all changes. The following is the test (or Main) script:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package
{
	import flash.display.Sprite;
	public class TestCol extends Sprite
	{
		private var headLights:ConcreteColleague1;
		private var panelLights:ConcreteColleague2;
		private var mediator:Mediator;
 
		public function TestCol()
		{
			headLights=new ConcreteColleague1();
			panelLights=new ConcreteColleague2();
			mediator=new ConcreteMediator();
			headLights.listenMediator(mediator);
			panelLights.listenMediator(mediator);
			headLights.doChange("on","col1");
			panelLights.doChange("on","col2");
		}
	}
}

When you run this script, you should see the following output:

?View Code ACTIONSCRIPT
1
2
3
4
5
__Concrete Colleague #1
__Concrete Colleague #2
Concrete Mediator: Coordinates Colleague Actions
Headlights are Bright
Console lights are Dim light

As the output indicates, the Colleague1 and Colleague2 classes are both invoked. Then the ConcreteMediator class is brought to life and its algorithm shuffles through the requests sent by the two colleague instances and sends out the appropriate information. To see if it really works, try changing the “on” parameter to “off” on the headlights and panelLights instances. You will see that the Mediator knows just what to do.

Next Steps

If you go back to Figure 1, you will see in the Mediator Interaction Design that colleague1 and colleague2 each have a single object reference to the mediator. That is pretty much what we’ve done here in terms of actually sending requests. No information is sent back to the colleagues from the Mediator. For example, the panel lights do not know that they are dimmed by the fact that the headlights were turned on. The mediator is taking care of that and there’s no reason to pass that information back to the colleague.

When looking at the actual design pattern implemented with a simple two-colleague model, all I can think about is how the concrete mediator class will grow in complexity as more and more colleagues are added to the mix. Indeed, GoF notes, The Mediator pattern trades complexity of interaction for complexity in the mediator (GoF, p. 277). My thoughts on this are, “No kidding!” The extent to which the different colleagues are unaffected by changes in other colleagues, you do not need a mediator. However, where your colleagues are heavily influenced by each others states, not only do you need a mediator, that mediator is going to be complex. The good thing is that all of the complexity is in one place (the mediator) and not strewn between the colleagues.

One alternative might be the State design pattern. (See Chapter 10, pg. 357 in ActionScript 3.0 Design Patterns) There each state class contains the states of the other state components. Not having given it too much thought, that seems like a reasonable alternative to one hugely complex class. True, as more and more states are added, each state class gets bigger; not just one as with the Mediator. Also, the Context class increases in complexity, not unlike the Mediator class, and so the result might actually be even more complex. However, when considering the Mediator, you might want to see if the State pattern might handle the job more appropriately and vice versa.

Right now, I’m hoping to get some feedback on the Mediator. I’d really like to hear others thoughts on some of these issues and see some alternative mediator designs. After spending a good deal of time with this pattern, I can see its functionality as well as its limitations. As with all design patterns, there’s a lot to be learned by working to understand them. This I found to be especially true with the Mediator.

Share
  1. February 6, 2009 at 12:49 am | #1

    I haven’t read much of the other patterns here, but this one seems like it would be quite good (and perhaps more appropriate) to manage a navigation setup, where different button states affect the other buttons (ie. on rollover of one menu item in the navigation, all the other buttons alpha out, or something along those lines)?

  2. February 6, 2009 at 9:37 am | #2

    Hi Regard,

    Take a look at the State Design Pattern for navigation too. Each state can be set up to affect all other states as well. In fact, that might be a good project for this blog.

    Thanks for your comment,
    Bill

  3. August 4, 2009 at 3:57 am | #3

    Hi Bill,

    nice article.

    The mediator pattern is all about communication. In your article you use the observer pattern with the mediator, which is a good implementation, but actually, they compete as ‘communication’ patterns.

    Observer/event based ‘communication’ patterns provide the loosest coupling, as they imply no knowledge at all of the user/client of the object.

    A mediator pattern uses knowledge about the mediator, thereby making the class that knows about the mediator tightly coupled to the mediator. Since the mediator itself is actually in most cases a very specific implementation (probably the Document class in flash, or a form of facade inside the application (a subapp), it is hard to make this pattern totally reusable. Especially when you call methods on the mediator that are mediator specific, such as “mediator.update(light, cn);”. While ‘update’ is a pretty generic name for a method, it’s still specific for this implementation with the current method signature.

    I would propose to do the dependency injection to the mediator at construction time: new Colleague(mediator);, as it serves no purpose to do so later, the setter method to inject the mediator will more probably than not be non-reuasable.

    Furthermore, I’d like to add that mediator is a form of doing callbacks on an object, which is just a form of delegation. Nothing new here, but it might provide a little more insight in the pattern.

    Your closing comment is very true “After spending a good deal of time with this pattern, I can see its functionality as well as its limitations.” I used to work a lot with mediators, but since flash’s event driven nature in as3, it’s kind of awkward to use this design pattern as opposed to the built in event/observer style of communication in flash.

  4. August 4, 2009 at 7:44 pm | #4

    Hi Rolf,

    Lots of food for thought there. Even given the event driven nature of AS3, you still have lots of possibilities for the Mediator in certain types of Flash/Flex applications. Why not use some of your background with the Mediator and enter the Golden Lunch Bucket Contest #3?

    Kindest regards,
    Bill

  5. September 17, 2010 at 8:59 am | #5

    Great post. Great book, too. One of my favorites.

    I’ve used the mvc, state, state machine and observers patterns for building flash video players. This combo works well for structuring mvc in flash, except that having so many object communicating with each other (eg, a play button view listening to the model) that managing all the interaction got messy quickly. I’m looking forward to using the Mediator pattern as well for future players I build.

    Is there a name for the pattern where Mediator uses Observer? I’d like to suggest Negotiator.

    • September 17, 2010 at 11:25 am | #6

      Hi Mitch,

      I definitely have to spend more time with the Mediator. Conceptually, it makes a lot of sense to me, but I’d like to do a better job of structuring it in an application.

      It’ll be a while before I’m at a place where I’d be comfortable using the Mediator with another pattern—-Observer or any other pattern.

      For me (but certainly not for most others), I would not use the MVC at all any more. Its functionality is subsumed by the Observer pattern in important ways, and the Observer is part of the catalog tied into a rationale for the patterns it contains. The MVC is the granddaddy that launched loose coupling, but I just don’t see it in more specific problem-solving.

      “Negotiator”–I really like that!! Mediator meets Observer: Result=>Negotiator!

      Cheers,
      Bill

  6. David H
    September 30, 2011 at 10:54 pm | #7

    In both your Colleague code examples, Colleague 1 and 2, you have a private member variable ‘om:Mediator’, yet that variable is never used in either class. So there are two issues, why didn’t you use that variable, and why in gods name would you instead choose to tack it on as a dynamic property of the colObj instead.

    • October 2, 2011 at 2:52 am | #8

      Hi Dave,

      The mediator objects (om) are properties of the Object instances (what you call ‘tacked on’) in both Concrete Colleagues and are used in changing the value of the “light” using the update() method. I used the Mediator (om) variable attached to an object so that I could use the Mediator method. I used the om variable with the object because I could not instantiate an abstract class (Mediator), but I could use it with an object.

      If you’re thinking….”Yuk!” I’d probably agree with you as far as a great example is concerned, but I wanted to get something that illustrated all of the parts of the Mediator design pattern. If you look at the previous reply to the previous comment you’ll see that I’m hoping to spend more time with the Mediator and come up with a better example. If you’d like to help out, you’re more than welcome.

      Kindest regards,
      Bill

  1. July 8, 2008 at 6:14 am | #1
  2. July 8, 2008 at 7:46 am | #2
  3. September 17, 2008 at 3:00 pm | #3

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>