The Mediator (Behavioral) Design Pattern
The Problem
One of the goals of object-oriented design is to distribute
behavior among different objects. This kind of partitioning is
good since it encourages reuse.
The Solution
Mediator is a behavioral pattern. This pattern helps to model a
class whose object at run-time is responsible for controlling and
coordinating the interactions of a group of other objects. It
helps encapsulate collective behavior in a separate mediator
object. Mediator promotes loose coupling by keeping objects from
referring to each other explicitly, and allowing the designer to
vary their interaction independently. Objects dont need to
know about each other, they just need to know their Mediator.
Mediators are generally used where complex protocols must be
managed, and when centralized access points are desirable. Thus,
as defined by Gamma et al, "A mediator serves as an
intermediary that keeps objects in a group from referring to each
other explicitly".
The Mediator provides a common connection point, centralized (and subclassable) behavior and behavior management, all with a common interface. As the number of colleagues increase, the number of total communication pathways is vastly reduced. The Mediator Pattern thus allows programs to organize the relationships and interactions between controls, frames, nonvisual objects and events in a controller class specifically tailored for an application.
Explanation
Example
Scenario 1 - One typical use of the Mediator Pattern in a
Microsoft Foundation Classes application: A dialog box presents a collection of
controls such as buttons, check boxes, list boxes, text fields
etc. There are often dependancies between these controls on a
dialog. For example, a disabled button gets enabled when text in
an edit box changes. Selecting an entry in a list-box may change
the contents of a text box. Once text appears in this field,
other menus may get enabled. Different dialogs have different
dependancies between the controls that they display. If each of
the controls (either the list boxes or edit boxes) were to be
coded with knowledge of other controls in the name of resolving
dialog-specific dependancies, the whole system would end up a
huge monolith mess. The problem can be solved by encapsulating
the collective behavior in a separate mediator object. This
mediator object would be responsible for controlling and
coordinating the interactions of a group of control objects. This
mediator object thus serves as an intermediary and prevents the
objects from referring to each other explicitly. MFC uses the
mediator pattern in the implementation of the CDialog class. Similarly, Java's AWT uses the
mediator pattern in the implementation of the java.awt.Dialog class.
For example, aFontDialog can be a mediator between aListBox
control and anEntryField edit control on a dialog box.
The aFontDialog object knows the controls in the dialog and coordinates their interaction. It acts as a hub of communication for these controls. The following object interaction diagram shows how the objects cooperate to handle a change in aListBox's selection.
|
Example
Scenario 2 - One typical use of the mediator pattern in COM/OLE: Font resources are shared data
structures, shared between applications and the GUI system. These
font resources may be quite large and complex. If the system had
a lot of components (either ActiveX or JavaBeans), each component
would have to allocate, manage and destroy their own font
resources. Every time each of these components repaint, they
would have to create the font, select it into the device context,
use it, select it out and then delete it. Imagine a container
having a number of such components each one doing this on every
repaint. It would be a hog on computing resources (both time
spent and memory used) devoted to performing this tedius and
inefficient task.
A separate mediator object can assist here by maintaining
ownership of a reuseable pool of font resources on an application
or system-wide basis without affecting the application or the GUI
system. It would also help if the mediator object could 'cache'
frequently-used fonts. This mediator object can thus act as a
centralized point of access. That is exactly how COM has
implemented it. The COM runtime sometimes acts as a mediator
object. COM uses the mediator pattern to implement the OleCreateFontIndirect() call. There are two interfaces you can
use to access the created font. The IFont interface provides a v-table method for accessing
font resources and the IFontDisp interface provides a dispatch interface
for accessing font resources.
The solution is so powerful and elegant that large graphic
bitmaps and other picture resources are also managed by
implementing the mediator pattern. COM uses the mediator pattern
in the implemention of the OleCreatePictureIndirect()
and
OleLoadPicture
() calls.
|
As mentioned earlier, the COM runtime acts as the mediator object, holding on to graphics resources that can be shared among a host of clients. There are two interfaces you can use to access the created graphics. The IPicture interface provides a v-table method of accessing graphics resources and the IPictureDisp interface provides a dispatch interface method of accessing graphics resources. The COM Runtime acts as a separate mediator object that assists by maintaining ownership of a reuseable pool of graphics resources on an application or system-wide basis without affecting the application or the GUI system. It thus acts as a centralized point of access serving up references to graphics resources to a lot of clients.
Participants
Mediator
(CDialog)
|
|
Concrete
Mediator (CChildDialog)
|
|
Colleague
classes (CListBox, CEdit)
|
Collaborations
Colleagues send and receive requests from the Mediator object.
The Mediator implements this co-operative behavior by serving as
a communications hub and routing requests between the appropriate
colleagues.
Checks and Balances of using this pattern
Plusses | Minus |
|
|
Notes on
Implementation
There is no need to define an abstract mediator class if all
colleagues are only going to work with one mediator. The
abstracting is only necessary when colleagues need to work with
different mediators.
Since Colleagues have to
communicate with their Mediator whenever an event of interest
occurs, there are different ways to implement the Mediator-Colleague
communication.
- The Mediator can be implemented as an Observer (using the Observer pattern) and the Colleagues as Subjects, which send notification to the mediator whenever a state change occurs. The Mediator then can propagate the effect of that change to other colleagues.
- The other approach is to use some form of delegation. When sending a message to the Mediator, the Colleague passes itself as an argument, thus allowing the mediator to identify the sender.
Source Code
We implement a Mediator which acts as a communications hub
between its colleagues. Our concrete mediator object, contains
two colleagues -'The OneColleague and the NextColleague'. Whenever the mediator's colleagueChanged() method is called (with a new Colleague passed in
as an argument), it compares the contents of the new colleague
with the contents of one of its colleagues (the OneColleague). If there is a match it sets the contents of its
other colleague (the NextColleague) to match the first colleague (the OneColleague).
The Class Diagram for our implementation with description is shown below:
Mediator
(Mediator)
|
|
Concrete
Mediator (ConcreteMediator)
|
|
Colleague
(Colleague)
|
|
Concrete
Colleague classes (OneColleague, NextColleague)
|
The Object interaction diagram with explanation is shown below:
|
Our source code implementation of the Mediator pattern coded in Java is shown below.
// // Mediator.java // import java.io.*; abstract class Mediator { public abstract void colleagueChanged(Colleague theChangedColleague); public static void main(String args[]) { ConcreteMediator aConcreteMediator = new ConcreteMediator(); aConcreteMediator.createConcreteMediator(); (aConcreteMediator.getOneColleage()).Display(); (aConcreteMediator.getNextColleague()).Display(); OneColleague newColleague = new OneColleague(aConcreteMediator, "OneColleague"); aConcreteMediator.colleagueChanged( (OneColleague)newColleague ); (aConcreteMediator.getOneColleage()).Display(); (aConcreteMediator.getNextColleague()).Display(); } } |
// // Colleague.java // abstract class Colleague { private Mediator _aMediator; public Colleague(Mediator m) { _aMediator = m; } public void changed() { _aMediator.colleagueChanged(this); } public Mediator getMediator() { return(_aMediator); } public abstract void Display(); } |
// // ConcreteMediator.java // class ConcreteMediator extends Mediator { private OneColleague _aOneColleague; private NextColleague _aNextColleague; public void colleagueChanged( Colleague theChangedColleague ) { if ((( OneColleague)theChangedColleague).getSelection().equals( _aOneColleague.getSelection() ) ) { _aNextColleague.setText( _aOneColleague.getSelection() ); } } public void createConcreteMediator() { _aOneColleague = new OneColleague(this, "OneColleague"); _aNextColleague = new NextColleague(this, "NextColleague"); } public OneColleague getOneColleage() { return(_aOneColleague); } public NextColleague getNextColleague() { return(_aNextColleague); } } |
// // OneColleague.java // class OneColleague extends Colleague { private String _text; public OneColleague(Mediator m, String t) { super( m ); _text = t; } public void setText(String text) { _text = text; } public String getSelection() { return(_text); } public void Display() { System.out.println("OneColleague = " + _text); } } |
Whenever
the mediator's colleagueChanged() method is called (with a new
Colleague passed in as an argument), it compares the
contents of the new colleague with the contents of one of
its colleagues (the OneColleague). If there is a match it sets the
contents of its other colleague (the NextColleague) to match the first colleague (the OneColleague). You can get the Java source files from here Mediator.zip Compile the files F:\MyProjects\Mediator > javac Mediator.java ConcreteMediator.java Colleague.java OneColleague.java NextColleague.java and run it with F:\MyProjects\Mediator > java Mediator OR If you have JBuilder c/s, open the mediator.jpr, compile and run it. |
// // NextColleague.java // class NextColleague extends Colleague { private String _text; public NextColleague(Mediator m, String t) { super( m ); _text = t; } public void setText(String text) { _text = text; } public String getSelection() { return( _text ); } public void Display() { System.out.println("NextColleague = " + _text); } } |
Also See
Facade and Observer.
This site was developed and is maintained by Gopalan Suresh Raj This page has been visited times since October 14,1998. |
Last Updated : Oct14, '98 |
Copyright (c) 1997-98, Gopalan Suresh Raj - All rights reserved. Terms of use. |
All products and companies mentioned at this site,are trademarks of their respective owners. |