Contents
Mediator
From GoF Define an object that
encapsulates how a set of objects interact. Mediator promotes loose coupling by
keeping objects from referring to each other explicitly. and allows you to vary
I find this diagram less than helpful.
A concrete example of Mediator:
[svs: Forgive the complex description; but that's when you use Mediator...]
I did a system a few years ago whose purpose was to
administer a gas pipeline, called the SILK pipeline which flowed gas between
two other pipelines: from the SEAL pipeline to the Interconnector. There were a
number of 'Shippers' who could put gas through the pipeline. They got the gas
from a number of other shippers (SEAL shippers). Each SILK shipper could get
gas from one or more of them. Each SILK shipper informed the SEAL pipeline
operator which SEAL Shipper was going to supply them and with how much. (They
did this on a daily basis, specifying for each day how much each hour would be
supplied, but that's not really relevant.) This notification was called a
Nomination. Similarly, the SEAL Shipper nominated to the SEAL operator how much
they were going to supply to each SILK Shipper.
At the other end of the pipeline the same thing happened.
The Shippers nominated to the Interconnector operator how much gas they were
going to deliver to and to whom (Interconnector shippers). The Interconnector
shippers also nominated to the Interconnector operator how much gas they were
going to receive and from whom.
All these nominations were copied to the SILK operator, the
user of this system.
At the end of the day, the SEAL pipeline operator worked out
how much gas had actually been entered into the SILK pipeline and told the SILK
operator. The Interconnector also told the SILK operator how much gas had come
out. The SILK operator now had to allocate this gas to the individual Shippers,
specifying how much of the input was credited to them � and from which SEAL
Shipper it was received � and how much of the output, and to which
Interconnector shipper it had gone.
These calculations were horrendously complex and depended on
whether the nomination from the SEAL shipper matched that from the SILK Shipper
(and similarly at the Interconnector end), whether there was a nomination from
both but the figure didn't match, or whether there was a nomination from one
but not the other. There were a number of objects involved � SEAL Shipper to
SILK Shipper, SILK from SEAL, SILK to Interconnector, Interconnector from SILK
(and all the hourly breakdowns). The logic for this matching process did not
belong in any of these objects.
The solution was to create a new object: AllocationMediator.
This knew about all these other objects and had the complex matching logic. It
had no permanent data, who had said what was going to happen and the totals
that had actually happened, and the rules for allocating those totals.
Relating this system to the diagram, there was only one
mediator thus there was no need for an abstract and concrete class, just a
concrete class. There were actually 9 colleagues � 4 Nomination types as input,
4 allocation types as output (the SEAL allocation types were also inputs to the
allocation at the Interconnector end), and a Silk Shipper Balance type also as
output.
This design allowed the 9 colleagues to exist without
knowing about any of the others. Thus when one changed all that had to change
was the AllocationMediator and not the other 8.
This was in one way a 'simple' Mediator: the Colleague
classes did not know about it (see the last point from GoF below). I still call
it a Mediator because of the complexity and number of rules it encapsulated; a
facade seems to me to be far more lightweight than this object was and also a
facade should totally encapsulate the colleagues, which this did not. Another
example of similarity in patterns: 'Is it a mediator? Is it a
Facade? Who
cares, it works!'.
Another often-quoted example of a Mediator is an object
which connects participants in a chat-room with each other.
Finally, if the logic in a mediator is switchable, consider
using a
Strategy pattern to provide the differing logic code if possible. If
not, you may need an abstract and a number of Concrete Mediators. If this in
turn isn't possible, try to break down the Mediator into simpler mediators
controlled by the main one (this could have been done in the pipeline example
above).
Points from GoF:
-
Chain of Responsibility,
Command, Mediator, and Observer, address how you can
decouple senders and receivers, but with different trade-offs. A
Chain of Responsibility passes a sender request along a chain of potential
receivers.
Command normally specifies a sender-receiver connection with a
subclass. Mediator has senders and receivers reference each other
indirectly. Observer defines a very decoupled interface that allows for
multiple receivers to be configured at run-time. [GOF, p347]
- Mediator
and Observer are competing patterns. The difference between them is that
Observer distributes communication by introducing 'observer' and
'subject' objects, whereas a Mediator object encapsulates the
communication between other objects. We've found it easier to make
reusable Observers and Subjects than to make reusable Mediators. [GOF,
p346]
- On
the other hand, Mediator can leverage Observer for dynamically registering
colleagues and communicating with them. [GOF, p282]
- Mediator
is similar to
Facade in that it abstracts functionality of existing
classes. Mediator abstracts/centralizes arbitrary communication between
colleague objects, it routinely 'adds value', and it is
known/referenced by the colleague objects (i.e. it defines a
multidirectional protocol). In contrast,
Facade defines a simpler
interface to a subsystem, it doesn't add new functionality, and it is not
known by the subsystem classes (i.e. it defines a unidirectional protocol
where it makes requests of the subsystem classes but not vice versa).
[GOF, p193]
From CodePro Java Patterns:
Use the Mediator pattern when
- a
set of objects communicate in well-defined but complex ways. The resulting
interdependencies are 'unstructured' and difficult to understand.
- re-using
or changing an object is difficult because it refers to and communicates
with many other objects.
- a
behaviour that's distributed between several classes should be
customizable without a lot of subclassing.
Various comments from around the Web:
- Typically
reduces the number of subclasses of colleague classes
- Reduces
/ loosens the bindings between colleague classes � the relationships are
moved to the mediator class(es)
- Simplifies
object relationships � many-to-many relationships are reduced to simpler
unidirectional associations
- Complex
interaction protocols are encapsulated by a single (ConcreteMediator)
object, simplifying the resulting design
- Mediators
may tend to become hard-to-maintain or enhanced �god� objects if given too
much centralized control
- The
Mediator pattern uses the Interface pattern to keep the Colleague classes
independent of the Mediator class. (This
is good advice for when the Colleagues need to know about the Mediator:
let them know about an Interface the mediator implements rather than the
mediator itself.)
- Omitting the
abstract Mediator class:
- The abstract coupling
that the Mediator class provides lets colleagues work with different
Mediator subclasses, and vice versa.
- When colleagues work
with only one type of Mediator, you don't need to define an abstract
Mediator class.
- Colleague-Mediator
communication:
Colleagues
communicate with their mediator when an event of interest occurs.
- One approach is to
implement the Mediator as an Observer using the Observer pattern.
- Colleagues act as
subjects notifying the mediator whenever they change state.
- The mediator
responds by propagating the effects of the change to other colleagues.