Skip to content

Mediator Pattern — Reduce Coupling Between Objects

DodaTech Updated 2026-06-24 4 min read

What You'll Learn

You will learn how the Mediator pattern centralises communication between components, preventing spaghetti of inter-component references and making the system easier to maintain. You will contrast Mediator with Observer and Facade.

Why It Matters

In a complex UI, a button click might update a status bar, disable a menu item, log the action, and refresh a data grid. Wiring each component directly to every other component creates a dense web of dependencies. Mediator routes all communication through a single coordinator. With a Mediator, the button only knows about the Mediator — it doesn't know about the status bar, menu, logger, or data grid. Adding a new component that reacts to button clicks requires no changes to the button.

Real-World Use

Air traffic control — planes communicate with the tower (Mediator), not directly with each other. DodaTech's workflow engine uses a Mediator to coordinate step completion, error propagation, and status updates across pipeline stages without coupling stages to each other. When a new monitoring stage is added to the pipeline, it simply registers with the Mediator; existing stages never need to know about it.

The Pattern

Mediator declares the communication interface. Colleague classes hold a reference to the Mediator. ConcreteMediator orchestrates interactions between colleagues.

from abc import ABC, abstractmethod

class AirTrafficMediator(ABC):
    @abstractmethod
    def send_message(self, sender: str, message: str) -> str:
        pass

    @abstractmethod
    def register_aircraft(self, name: str):
        pass

class ControlTower(AirTrafficMediator):
    def __init__(self):
        self._aircraft = set()

    def register_aircraft(self, name: str):
        self._aircraft.add(name)

    def send_message(self, sender: str, message: str) -> str:
        responses = []
        for ac in self._aircraft:
            if ac != sender:
                responses.append(f"{ac} received from {sender}: {message}")
        return "\n".join(responses)

class Aircraft:
    def __init__(self, name: str, mediator: AirTrafficMediator):
        self._name = name
        self._mediator = mediator
        mediator.register_aircraft(name)

    def send(self, message: str) -> str:
        return self._mediator.send_message(self._name, message)
tower = ControlTower()
a1 = Aircraft("Flight 101", tower)
a2 = Aircraft("Flight 202", tower)
a3 = Aircraft("Flight 303", tower)
print(a1.send("Landing request, runway 4"))
Flight 202 received from Flight 101: Landing request, runway 4
Flight 303 received from Flight 101: Landing request, runway 4

Structure

classDiagram
    class Mediator {
        <>
        +notify(sender, event)
    }
    class ConcreteMediator {
        +notify(sender, event)
    }
    class Colleague1 {
        +operation()
    }
    class Colleague2 {
        +operation()
    }
    ConcreteMediator ..|> Mediator
    ConcreteMediator --> Colleague1 : manages
    ConcreteMediator --> Colleague2 : manages
    Colleague1 --> Mediator : communicates via
    Colleague2 --> Mediator : communicates via

Real-World Usage

  • UI dialog components — a dialog Mediator enables/disables buttons, validates inputs, and shows error messages without buttons knowing about text fields.
  • Python's signal module — signals are mediated between senders and registered handlers.
  • Message brokers (RabbitMQ, Kafka) — decouple producers from consumers through a message-oriented Mediator.
  • JavaScript event bus / pub-sub — Vue.js event bus or Node.js EventEmitter act as mediators between components.
  • Observer enables one-to-many notification; Mediator centralises many-to-many communication.
  • Facade simplifies a subsystem interface; Mediator coordinates subsystem components.
  • Chain of Responsibility passes a request sequentially; Mediator broadcasts to multiple colleagues.
  • Command encapsulates a request; Mediator decides which command to invoke.

Pros and Cons

Pros Cons
Reduces coupling between colleague classes Mediator can become a god object with too many responsibilities
Centralises communication logic Indirect communication can hurt performance
Easy to add new colleagues without changing others Debugging is harder since the call flow is hidden
Simplifies protocols between components Mediator's interface may need frequent changes

The air traffic control example shows that Aircraft instances never communicate directly. They hold a reference to the ControlTower Mediator and send messages through it. The Mediator then broadcasts to all other aircraft. This decoupling means adding new aircraft (colleagues) requires no changes to existing aircraft classes.

Practice Questions

  1. Implement a chat room Mediator where users can send private messages to specific users and broadcast messages to all users.
  2. When does Mediator become an anti-pattern, and how would you decompose a large Mediator into smaller, focused ones?
  3. Compare Mediator with Observer — which would you use for a form validation system?
  4. How would you implement an undoable Mediator that can roll back interactions if a later step fails?

Challenge

Implement a Mediator for a modal dialog where three fields validate each other (e.g., start date must be before end date, end date must be after start date). The Mediator should coordinate validation across all three fields without the fields knowing about each other.

Real-World Task

Run DodaTech's dependency matrix on a UI-heavy module in your application. Identify components that reference three or more other components directly. Refactor the communication through a Mediator and re-run the matrix to measure coupling reduction.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro