Skip to content

// Design Patterns · 17

Mediator

Components call each otherleads toAll talk via one mediator

Route interactions through one object instead of a web of calls.

How it fits together

Mediator structureCountryPicker«interface»CheckoutMediatorChanged(sender)CheckoutFormMediatorcountry → shippingshipping → paymentShippingOptionsPaymentMethods1 changed2 reload3 changed4 reload
implementspublishes / notifiesuses / calls· numbered steps replay in order
  • CheckoutFormMediator implements CheckoutMediator
  • CountryPicker publishes / notifies CheckoutFormMediator (1 changed)
  • CheckoutFormMediator uses / calls ShippingOptions (2 reload)
  • ShippingOptions publishes / notifies CheckoutFormMediator (3 changed)
  • CheckoutFormMediator uses / calls PaymentMethods (4 reload)

Spot it

  • Every widget references every other widget
  • Changing one component breaks three others
  • Interaction rules scattered across classes

It costs

Coupling moves into the mediator, which can grow into a god object.

In code

public interface ICheckoutMediator{    Task ChangedAsync(object sender, CancellationToken ct);}​public sealed class CheckoutFormMediator(    CountryPicker country,    ShippingOptions shipping,    PaymentMethods payment) : ICheckoutMediator{    public async Task ChangedAsync(object sender, CancellationToken ct)    {        switch (sender)        {            case CountryPicker:                await shipping.ReloadAsync(country.Selected, ct);                break;            case ShippingOptions:                await payment.ReloadAsync(country.Selected, shipping.Selected, ct);                break;        }    }}
Go deeperThe full explanation and what to ask for · 1 min readExpand

A mediator encapsulates how a set of objects interact. Colleagues no longer reference each other; they tell the mediator that something happened, and it decides who reacts. A many-to-many web becomes one-to-many, and the interaction rules live in one place.

The mediator concentrates coupling rather than removing it, so keep it to coordination and push real work back into the colleagues. A single application-wide dispatcher that routes every request is a different thing, an in-process message bus, which hides call paths without adding this kind of coordination.

Observer distributes communication: a subject broadcasts and anyone may subscribe, with nobody owning the rules. Mediator centralises it: one object knows the colleagues and the order of reactions, often receiving their notifications observer-style. Facade also fronts several objects, but they do not know it exists and calls flow one way.

Ask for it

  • mediator
  • colleague
  • many-to-many → one-to-many
  • coordination logic
  • event aggregator

In the checkout form, the country, shipping and payment components update each other directly. Add a CheckoutMediator that each component notifies with Changed(sender), and let it decide what to reload (country → shipping options → payment methods). Components may only reference the mediator.