Type Behavioral
Purpose The Mediator defines an object that controls how a set of objects interact. Loose coupling between colleague objects is achieved by having colleagues communicate with the Mediator, rather than one another.

Description

The Mediator pattern is a behavioural design pattern that centralises communication between related objects by preventing them from referring to one another directly. Instead of communicating with each other explicitly, the participating objects interact through a mediator.

This reduces direct dependencies between colleagues and helps keep the system more loosely coupled. As a result, interactions become easier to manage, extend, and modify without requiring widespread changes across the collaborating objects.

Mediator is particularly useful when a set of objects interacts in complex ways and those interactions would otherwise lead to a tangled web of references and responsibilities.

Mediator is primarily concerned with encapsulating how objects interact.


Overview

Mediator
Mediator This interface defines a method that is used to communicate between colleagues.
ConcreteMediator Implements the Mediator interface and coordinates communication between the colleague objects.
Colleagues These are the classes that need to communicate with each other. They don't communicate directly, but instead communicate through the mediator. Each colleague maintains a reference to the mediator through which it can initiate communication with other colleagues.

Implementation

In the following classic example, an Airbus aircraft encounters a problem and sends a distress signal to the ATC tower, which acts as the mediator. The mediator then relays the warning to the other aircraft, excluding the sender. In this arrangement, the aircraft do not communicate directly with one another; all communication passes through the mediator.

This reduces the complexity of the interaction model, since each participant needs to know only about the mediator rather than about every other participant in the system. The result is looser coupling and a clearer separation of responsibilities, both of which are characteristic of well-structured design.

This arrangement also resembles aspects of Message Bus architecture, since participants communicate indirectly through an intermediary. The responsibilities differ, however: a Mediator typically encapsulates and coordinates interactions between specific colleagues, whereas a Message Bus primarily provides infrastructure for exchanging messages between otherwise decoupled participants.

// Mediator

public interface IAirTrafficControl
{
    void RegisterAirplane(Airplane airplane);
    void SendWarningMessage(Airplane airplane, string message);
}

// Concrete Mediator

public class AirTrafficControlTower : IAirTrafficControl
{
    private readonly List<Airplane> _airplanes = [];

    public void RegisterAirplane(Airplane airplane) => _airplanes.Add(airplane);

    public void SendWarningMessage(Airplane airplane, string message)
    {
        foreach (var a in _airplanes.Except([airplane]))
        {
            a.ReceiveMessage(message);
        }
    }
}

// Colleague

public abstract class Airplane
{
    protected readonly IAirTrafficControl ControlTower;

    protected Airplane(IAirTrafficControl controlTower)
    {
        ControlTower = controlTower;
        ControlTower.RegisterAirplane(this);
    }

    public abstract void ReceiveMessage(string message);
    public abstract void SendMessage(string message);
}

// Concrete Colleague

public class Airbus(IAirTrafficControl controlTower) : Airplane(controlTower)
{
    public override void ReceiveMessage(string message)
        => Console.WriteLine($"Airbus received: {message}");

    public override void SendMessage(string message)
    {
        Console.WriteLine("Airbus sends message to Control Tower");
        ControlTower.SendWarningMessage(this, message);
    }
}

// Concrete Colleague

public class Boeing(IAirTrafficControl controlTower) : Airplane(controlTower)
{
    public override void ReceiveMessage(string message)
        => Console.WriteLine($"Boeing received: {message}");

    public override void SendMessage(string message)
    {
        Console.WriteLine("Boeing sends message to Control Tower");
        ControlTower.SendWarningMessage(this, message);
    }
}

// Client

public static class MediatorDemo
{
    public static void Execute()
    {
        var atcTower = new AirTrafficControlTower();
        var airbus = new Airbus(atcTower);
        var boeing = new Boeing(atcTower);

        airbus.SendMessage("Mayday, mayday! Lost control.");
    }
}

Summary

For more information, please see here.