Mediator
The Mediator pattern defines a Mediator object that controls how a set of objects interact. So instead of having tight coupling between a set of objects that all refer to each other, each object only needs to know about the Mediator, and their interaction can very independently.
This pattern is a good way to refactor a system that has many interconnections between objects. This usually means that the behaviour of the system is spread between many objects, which can make it hard to change any behaviour. When you have a system like this you would usually be forced to create many subclasses to change behaviour. The Mediator pattern provides a cleaner alternative.
Contents |
Usage
Use Mediator when:
- You have a set of objects that communicate in a complex manner with many interdependencies.
- It is hard to reuse an object because it communicates with many others.
- You want to customise a behaviour without creating a lot more subclasses, but it is spread over several objects.
Structure
Mediator: Defines an interface for communicating with Colleague objects.
ConcreteMediator: Knows and maintains its Colleagues. Implements communication behaviour between Colleague objects by routing requests to and from the appropriate Colleagues.
Colleague: Know its Mediator object. Communicates with its Mediator whenever it originally would have communicated with another Colleague.
Note that Colleagues have to update the Mediator class when an event of interest occurs, this is a perfect pattern to combine with the Observer pattern. Mediator is the Observer, and Colleagues are Subjects.
Example
The Gang of Four describe a dialog box as an example. A dialog box contains many different Widget objects such as buttons, list boxes, and text fields. Often different widgets of a dialog box depend on each other, for example selecting an entry in a list box may update the contents of a text field. On the other hand, typing in the text field may update the selected item in the list box.
Different dialog boxes will require different dependencies between Widgets. Creating new subclasses to customise dialog-specific dependencies would be very tedious and you would have far too many subclasses in your design. The solution is to encapsulate the collective behaviour in the Mediator object, reducing the number of inter-dependencies.
Here is the example class diagram from the Gang of Four book with the corresponding interaction diagram:
DialogDirector is the abstract Mediator class that defines the overall behaviour of the dialog box. WidgetChanged() is what Widgets call to inform the Mediator that they have changed. Subclasses of DialogDirector override WidgetChanged() to handle the changes. Widget is the abstract Colleague class.
The ListBox tells the FontDialogDirector that it has changed. The Director gets the selection from the ListBox. The Director passes the selection to the EntryField.
Consequences
- Limits sublclassing - only requires subclassing Mediator class to change behaviour instead of creating multiple subclasses .
- Promotes loose coupling between Colleague classes, which means they can be reused easier.
- Simplifies many-to-many relationships to one-to-many between the Mediator and Colleagues. One-to-many relationships are easier to understand and maintain.
- Abstracts how objects interact, making the system easier to understand.
- Drawback: control is centralized to the Mediator class. This is a tradeoff between complexity of interaction and complexity of the Mediator class. The Mediator class can become very complex.
Design patterns | |
---|---|
Creational: Abstract Factory | Builder | Factory Method | Prototype | Singleton |