Mediator Pattern in C#

The Mediator Pattern defines an object that centralises communication between components. Instead of components talking directly to each other, they send messages through the mediator. This helps reduce dependencies and makes the system easier to manage.

Real-Life Analogy: Air Traffic Controller

In an airport, planes don't communicate directly with each other. They all speak to the control tower — the air traffic controller decides who can take off or land.

This avoids chaos and keeps everything organised. That's what the Mediator Pattern does in software: it acts as the central authority that manages interaction.

Air traffic controller coordinating communication between planes
Like an air traffic controller managing multiple planes, the Mediator Pattern coordinates how components interact.

Benefits of Mediator Pattern

When many components interact directly, you end up with tangled dependencies. The Mediator Pattern simplifies things by putting all communication in one place — the mediator.

This makes your system easier to understand and extend.

  • Reduces coupling between components
  • Centralises control and communication
  • Makes components easier to reuse and test

When Should You Use It?

Use the Mediator Pattern when many objects interact in complex ways, and you want to reduce direct references between them. It's great when components need to work together but shouldn't know about each other.

It suits:

  • UI forms where controls update each other
  • Message buses or chat room logic
  • Scenarios where objects coordinate frequently

When Not to Use It: Avoid it if there are only a few simple interactions — the mediator adds unnecessary complexity.

What to Implement

To use the Mediator Pattern, you need:

A mediator interface, a concrete mediator to manage components, and participant classes that use the mediator instead of talking directly.

  • Colleague Interface: Shared by all participants
  • Concrete Colleagues: Perform tasks and call the mediator
  • Mediator Interface: Defines how components communicate
  • Concrete Mediator: Coordinates who talks to whom

How It Works in C#


// Mediator Interface
public interface IAirTrafficControl
{
    void Notify(string message, Plane sender);
}

// Colleague
public abstract class Plane
{
    protected IAirTrafficControl control;

    public Plane(IAirTrafficControl control) => this.control = control;

    public abstract void Receive(string message);
}

// Concrete Colleagues
public class PassengerPlane : Plane
{
    public PassengerPlane(IAirTrafficControl control) : base(control) { }

    public override void Receive(string message)
    {
        Console.WriteLine($"Passenger Plane received: {message}");
    }

    public void Send(string message)
    {
        control.Notify(message, this);
    }
}

public class CargoPlane : Plane
{
    public CargoPlane(IAirTrafficControl control) : base(control) { }

    public override void Receive(string message)
    {
        Console.WriteLine($"Cargo Plane received: {message}");
    }
}

// Concrete Mediator
public class ControlTower : IAirTrafficControl
{
    private List<Plane> planes = new();

    public void Register(Plane plane) => planes.Add(plane);

    public void Notify(string message, Plane sender)
    {
        foreach (var p in planes)
        {
            if (p != sender)
                p.Receive(message);
        }
    }
}

Usage:


var tower = new ControlTower();

var passenger = new PassengerPlane(tower);
var cargo = new CargoPlane(tower);

tower.Register(passenger);
tower.Register(cargo);

passenger.Send("Requesting takeoff clearance");

Final Thoughts

The Mediator Pattern is perfect when many objects need to interact, but you want to avoid direct dependencies. It brings order to communication chaos and makes systems easier to scale and maintain.

Like an air traffic controller, it ensures every message gets to the right destination safely and clearly.