Behavioral Patterns «Prev Next»

Lesson 11Mediator: structure
ObjectiveIdentify the participants in the Mediator pattern and trace how they coordinate an interaction.

Mediator Pattern Structure: Participants and Communication Flow

The Mediator pattern is a behavioral design pattern that encapsulates how a cohesive set of objects interact. Instead of every participating object knowing and invoking several peers, colleagues report events or requests through a mediator. The mediator applies the collaboration rules and invokes the appropriate colleagues.

Mediator does not remove all coupling. It replaces many concrete colleague-to-colleague dependencies with a dependency on a mediator. Interaction complexity remains, but it is localized for inspection, testing, and deliberate change. Colleague is the classic Gang of Four term; production code often uses names such as component, control, device, participant, or service.

Participants in the Mediator Pattern

Mediator
The Mediator defines operations through which colleagues report events or request coordination. An interface defines communication operations; it does not normally store colleague references. References, registration tables, and workflow state belong to a concrete implementation or its registry.
ConcreteMediator
The ConcreteMediator implements the contract and owns collaboration rules. It may keep fixed references, register dynamic participants, validate requests, sequence operations, and translate one colleague's event into actions on others. It should coordinate without absorbing all domain behavior. A mediator that collects unrelated policies risks becoming a god object and should be divided by cohesive workflow.
Colleague
The Colleague represents the communication capabilities expected of participants. It commonly knows its mediator, reports relevant events, and exposes focused operations. A shared abstract class is optional; Java can instead use an interface, composition, or an existing framework base class. Do not add inheritance merely to imitate a diagram.
ConcreteColleague
Each ConcreteColleague performs one participant's local behavior. A text field owns its text, a button its enabled state, and a signal its displayed aspect. It reports meaningful events to the mediator without needing the complete policy or references to every peer. Concrete colleagues can have different APIs.

A contract can be generic, such as componentChanged(source, event), or domain-specific, such as requestLanding(aircraft). Generic operations accommodate new event types but may require runtime branching. Domain-specific methods express clearer intent but can enlarge the contract.

What Each Participant Knows

ParticipantUsually knowsShould not need to know
Mediator interfaceThe operations colleagues use to communicateConcrete colleague instances or storage details
Concrete mediatorParticipating colleagues and collaboration rulesUnrelated domain behavior outside the collaboration
Colleague abstractionThe mediator contract or a narrow communication portEvery concrete peer type
Concrete colleagueIts own state, behavior, and mediator-facing eventsThe complete interaction graph and global coordination policy

The pattern rearranges dependency direction. Directly connected colleagues reference peers and embed assumptions about them. Mediated colleagues usually depend on a mediator abstraction, while the concrete mediator is composed with the participants. A client or composition root connects the objects.

A concrete mediator does not always need a field for every colleague. Fixed collaborations often use named fields; dynamic systems may use registration, lookup tables, groups, or routing metadata. A colleague can pass itself with an event, or a typed callback can identify the source.

Interpreting the Mediator Structure

Mediator pattern with 4 Front End objects and 5 Back End Objects.
Mediator pattern with 4 Front End objects and 5 Back End Objects.

The diagram places a mediator between front-end and back-end colleagues. Front-end participants might be controls or views; back-end participants might be domain objects, services, repositories, or models. The mediator receives an event, determines what it requires, and coordinates only the affected participants.

In a word processor, moving a scroll bar can update a viewport without changing stored text. Editing text can update the model and refresh appropriate views. This is selective coordination, not indiscriminate broadcasting. Mediator can also coordinate dialog controls, aircraft, workflow steps, smart-home devices, or chat participants.


API Design Patterns

How a Mediated Interaction Proceeds

  1. A concrete colleague detects a local event, such as edited text or a button click.
  2. The colleague reports the event to the mediator instead of invoking several peers directly.
  3. The concrete mediator validates the event and evaluates the collaboration's current state.
  4. The mediator invokes one or more colleague operations in the required order.
  5. Each target colleague performs its focused behavior and may report a resulting event if another coordination step is required.

Steps four and five require a reentrancy policy because one action can produce another event during processing. Safeguards include separating commands from notifications, suppressing unchanged values, queuing nested events, or modeling legal state transitions. Otherwise, the collaboration can enter a cycle.

Events should communicate intent. emailChanged() is clearer than notify("changed"), and submitRequested() is clearer than arbitrary strings. Typed events reduce errors and reveal supported interactions.

Java Example: Coordinating Form Components

In this example, an email field and submit button never reference each other. Both report through a mediator. The concrete mediator enables the button only when the field contains a plausible address and processes a submission request.

public final class MediatorStructureDemo {
    enum Event {
        EMAIL_CHANGED,
        SUBMIT_REQUESTED
    }
    interface Mediator {
        void componentChanged(Component source, Event event);
    }
    abstract static class Component {
        private final Mediator mediator;
        protected Component(Mediator mediator) {
            this.mediator = mediator;
        }
        protected final void report(Event event) {
            mediator.componentChanged(this, event);
        }
    }
    static final class EmailField extends Component {
        private String text = "";
        EmailField(Mediator mediator) {
            super(mediator);
        }
        void enterText(String text) {
            this.text = text;
            report(Event.EMAIL_CHANGED);
        }
        String text() {
            return text;
        }
    }
    static final class SubmitButton extends Component {
        private boolean enabled;
        SubmitButton(Mediator mediator) {
            super(mediator);
        }
        void setEnabled(boolean enabled) {
            this.enabled = enabled;
            System.out.println("Submit enabled: " + enabled);
        }
        void click() {
            if (enabled) {
                report(Event.SUBMIT_REQUESTED);
            } else {
                System.out.println("Submission blocked.");
            }
        }
    }
    static final class RegistrationForm implements Mediator {
        private final EmailField emailField = new EmailField(this);
        private final SubmitButton submitButton = new SubmitButton(this);
        EmailField emailField() {
            return emailField;
        }
        SubmitButton submitButton() {
            return submitButton;
        }
        @Override
        public void componentChanged(Component source, Event event) {
            if (source == emailField && event == Event.EMAIL_CHANGED) {
                submitButton.setEnabled(emailField.text().contains("@"));
            } else if (source == submitButton && event == Event.SUBMIT_REQUESTED) {
                System.out.println("Registered: " + emailField.text());
            }
        }
    }
    public static void main(String[] args) {
        RegistrationForm form = new RegistrationForm();
        form.submitButton().click();
        form.emailField().enterText("alice@example.com");
        form.submitButton().click();
    }
}

Expected Output

Submission blocked.
Submit enabled: true
Registered: alice@example.com

Mediator is the contract, and RegistrationForm is the concrete mediator that owns the colleagues and form policy. Component is an optional colleague base class. EmailField and SubmitButton are concrete colleagues. The main method is the client.

The contains("@") check is intentionally minimal, not production validation. This is Mediator rather than Observer because the button does not subscribe to the field and the field does not broadcast to dependents. Both use RegistrationForm, which applies interaction policy.

Composition Is More Important Than Inheritance

Mediator has a less rigid inheritance structure than some patterns. Colleagues communicate through a mediator, the mediator owns interaction policy, and colleagues retain local responsibilities. Production code does not require four source files or literal GoF class names. Preserve responsibilities and dependency direction.

A concrete mediator can create fixed colleagues, as in the example, or receive them from a composition root. Dynamic participants can be registered and removed. Constructor self-registration can obscure ownership, expose a partially constructed object, and complicate removal.

Structural Benefits and Consequences

The concrete mediator is coupled to the operations it coordinates and can become too large. Centralized policy can hide runtime effects. A synchronous mediator can become a failure or performance bottleneck. Dynamic registration introduces lifecycle concerns, while concurrency requires rules for synchronization, ordering, cancellation, and failure isolation.

Mediator reduces direct interconnections and reallocates responsibilities. It may reduce subclassing used only to change coordination, but that is not a defining guarantee.

From Direct Connections to Coordinated Collaboration

Before mediation, colleagues may contain direct references to one another, producing a dense graph. In a fully connected group of n colleagues, potential pairs grow approximately as n(n - 1) / 2. Mediation replaces many peer relationships with roughly one per colleague, while the concrete mediator bears the cost of understanding the collaboration.

The mediator is more than a target interface; it makes routing, validation, and sequencing decisions. Retain direct relationships when they are simple and stable. Introduce Mediator when many-object interaction policy causes change or complexity.

Loose Coupling in the Mediator Structure

Loose coupling limits concrete knowledge and change propagation. A colleague can change without forcing every peer to change when its mediator contract remains stable. Coupling still exists: colleagues depend on the contract, and the concrete mediator depends on required colleague operations. The goal is intentional, stable dependencies.



Mediator Compared with Related Patterns

PatternPrimary purposeDifference from Mediator
ObserverNotify dependents when a subject changesMediator owns collaboration policy among peers; Observer distributes state-change notifications to subscribers.
FacadeProvide a simpler entry point to a subsystemA facade is mainly used from outside a subsystem; a mediator coordinates participating objects.
CommandRepresent a request as an objectA mediator may route commands, but Command encapsulates a request and can support queuing, logging, or undo.
ControllerHandle input or application flow in an architectural roleA controller can act as a mediator, but not every controller represents the GoF collaboration structure.

Pattern names describe responsibilities, not framework annotations. One class can participate in more than one pattern when its responsibilities remain explicit and cohesive.

Reviewing a Mediator Design

A sound Mediator structure gives each participant a clear reason to change. Colleagues change when their local behavior changes, while the mediator changes when collaboration policy changes. That separation, rather than a prescribed inheritance hierarchy, is the pattern's central structural value.


SEMrush Software 11 SEMrush Banner 11