What is the intent of the Mediator design pattern, and what kind of coupling problem does it address?
answer
- Colleagues know only the mediator
- Mesh N*(N-1) → star N links
- Protocol lives in one named place
- Dialog box: fields report, dialog decides
- Cost: god-object + indirection
basics
~20 sMediator defines one object that encapsulates how a group of objects interact. Instead of each object calling the others directly, they all talk to the mediator. That turns tangled many-to-many links into simple one-to-many links.
solid answer
~40 sMediator is a behavioral pattern whose intent is to "define an object that encapsulates how a set of objects interact". The interacting objects are called colleagues. Without a mediator, each colleague holds references to the colleagues it must notify, so N collaborating objects can approach N*(N-1) directed links — a many-to-many web where every new colleague touches existing ones. With a mediator, each colleague knows only the mediator; the mediator knows all colleagues and holds the interaction rules. Coupling drops from many-to-many to many-to-one (a star topology), colleagues become individually reusable and unit-testable, and the interaction protocol becomes explicit and changeable in one place rather than being smeared across participants. The classic example is a dialog box: fields do not enable/disable each other; they report changes to the dialog, which applies the rules.
code
pseudocode · 16 linesinterface Mediator { notify(sender, event) }
class FormMediator implements Mediator {
country; state; postal; submit
notify(sender, event) {
if (sender == country && event == "changed") {
state.reloadFor(country.value); postal.clear()
}
submit.enabled = country.valid && state.valid && postal.valid
}
}
class Dropdown {
mediator
onChange() { mediator.notify(this, "changed") } // knows nobody else
}go deeper
State the intent (one object encapsulates how a set of objects interact), name colleague and mediator, and give the dialog-box or chat-room example.
Add the coupling arithmetic (mesh vs star), the participant roles including the abstract Mediator interface, and contrast with Observer and Facade.
Discuss when it is worth it: rules-heavy interaction, several colleagues, frequent protocol change — plus the god-object cost and how you keep the mediator small.
Frame it as a topology decision that recurs at every scale (UI controller, service orchestrator, message broker, service mesh) and reason about when centralizing a protocol creates a bottleneck or single point of failure.
## The problem Imagine a set of objects that must react to each other. A form has a country dropdown, a state dropdown, a postal-code field, and a Submit button. The rules are: choosing a country reloads the state list, clearing state clears postal code, and Submit is enabled only when all are valid. The naive implementation gives each widget references to the widgets it must poke: the country dropdown calls `stateList.reload()` and `submit.recheck()`, the state dropdown calls `postal.clear()` and `submit.recheck()`, and so on. Two consequences follow: 1. **Coupling explodes.** Any colleague may need a reference to any other, so the number of possible directed links grows quadratically — N*(N-1) for N colleagues. Adding a new field means editing several existing ones. 2. **The protocol becomes invisible.** The rule "changing country clears the postal code" does not live anywhere; it is an emergent property of scattered calls. Nobody can read the interaction as a whole, and nobody can change it safely. Colleagues also stop being reusable: the state dropdown cannot be dropped into another form because it hard-references *this* form's postal field. ## The pattern **Mediator** (Gang of Four, behavioral) introduces one object that owns the interaction: - **Mediator** — an interface declaring how colleagues report events, classically a single `notify(sender, event)` method (GoF calls it `ChangeAware`/`WidgetChanged`; modern code often names it `notify`, `handle`, or `dispatch`). - **ConcreteMediator** — implements the interaction logic; holds references to all colleagues and coordinates them. - **Colleague** — each participating object; holds a reference to the mediator only. When something interesting happens it calls `mediator.notify(this, event)` and lets the mediator decide who else must react. Topology changes from a **mesh** to a **star**: N colleague→mediator links instead of up to N*(N-1) colleague→colleague links. ## What you actually gain - **Single Responsibility.** Interaction rules move out of the participants into one class that has a name and can be read top to bottom. - **Open/Closed for colleagues.** Adding a colleague changes the mediator, not the other colleagues. - **Reusability.** A colleague depends on an abstract mediator interface, so it can be used in any context that supplies one. - **Testability.** Colleagues can be tested against a stub mediator; the mediator can be tested against stub colleagues, and the protocol assertions live in one test suite. ## What you pay - **God-object risk.** All the interaction logic converges on one class. Unchecked, the mediator becomes a huge, high-churn class that knows every colleague — you traded a distributed mess for a centralized one. - **Indirection.** Reading the flow requires a hop through the mediator; stack traces and "who called this?" navigation get longer. - **Not a decoupling of *knowledge*, only of *references*.** The mediator still knows every colleague; complexity is relocated, not deleted. ## Boundaries with neighbours - **Observer** decouples a subject from unknown subscribers via broadcast; a mediator knows its colleagues by name and applies *rules* between them. Many mediators are *implemented* using observer-style subscriptions. - **Facade** simplifies access to a subsystem for outside callers, and the subsystem does not know the facade; mediator members *do* know and call the mediator, and communication is bidirectional. - **Command** encapsulates a single request as an object; Mediator encapsulates the whole conversation. ## Rule of thumb Reach for Mediator when the interaction rules — not the individual behaviours — are the complicated part, and when you find yourself editing several classes to change one rule. Skip it when only two objects talk, or when the interaction is a simple broadcast (plain Observer is lighter).
- How is Mediator different from Facade, since both add an object in front of a group of objects?Direction and awareness. A facade is a one-way convenience entry point for *external* clients; the subsystem classes do not know the facade exists and keep talking to each other. With a mediator the participants explicitly depend on it and communication is bidirectional — they report to it and it calls them back — because its job is to own the interaction protocol, not to simplify an API surface.
- Does Mediator reduce total system complexity?No — it relocates it. The number of interaction rules is unchanged; they are moved from many colleagues into one place where they are visible and editable. The win is comprehensibility and localized change, not less logic. If the mediator is left to grow unbounded, you get a single god object instead of a distributed mess.
Air-traffic control. Pilots do not negotiate landing order with each other over the radio — that would be N*(N-1) conversations and chaos. Each pilot talks only to the tower; the tower knows every aircraft and owns the sequencing rules.