AlgoMaster Logo

Mediator Design Pattern

Ashish

Ashish Pratap Singh

5 min read

The Mediator Design Pattern is a behavioral pattern that defines an object (the Mediator) to encapsulate how a set of objects interact.

It promotes loose coupling by preventing objects from referring to each other directly, and lets you vary their interactions independently.

It’s particularly useful in situations where:

  • You have a group of tightly coupled classes or UI components that need to communicate.
  • Changes in one component require updates in multiple others.
  • You want to centralize communication logic to simplify maintenance and testing.

When classes depend on each other directly, their interactions often become tangled.

For example, in a GUI form, when a user types into a field, it may enable or disable a button, update a label, and trigger validation — each component talking to the others directly.

But as more components are added, this direct communication becomes hard to manage, creates spaghetti code, and each component ends up handling its own logic plus knowledge of how to coordinate with others.

The Mediator Pattern solves this by introducing a central object that handles communication between components. Each component interacts only with the mediator, which coordinates and manages interactions — reducing coupling and simplifying each component’s logic.

Let’s walk through a real-world example to see how we can apply the Mediator Pattern to build a more modular, loosely coupled system where components communicate cleanly and consistently.

1. The Problem: Tightly Coupled UI Components

Imagine you're building a login form with the following UI components:

  • username field
  • password field
  • login button
  • status label

The logic of the form is simple:

  • The login button should be enabled only when both username and password fields are non-empty.
  • When the button is clicked, it should attempt login and display the result in the status label.

Sounds simple, right? Let’s try implementing this with each component talking directly to the others.

TextField

Button

Label

What’s Wrong with This Design?

At first glance, this seems fine. But as soon as you add a few more components (e.g., remember me checkbox, forgot password link), the logic starts to spiral out of control.

1. Tight Coupling

Every component knows about others: the TextField knows the Button, the Button knows the TextField and the Label. A change in one component's logic often requires updates in others — creating a fragile system.

2. Lack of Reusability

You can’t easily reuse these components elsewhere. They’re hard-wired to interact with specific peers, making them context-dependent.

3. Poor Maintainability

Adding or modifying interactions requires changing the logic of multiple classes. This violates the Open/Closed Principle and makes the system harder to test and evolve.

4. Hidden Logic Sprawled Across Components

Each component contains not only its own logic, but also coordinating behavior, making it harder to isolate responsibilities.

What We Really Need

We need a way to:

  • Decouple UI components from each other
  • Centralize the coordination logic so that each component focuses only on its own role
  • Make it easier to add, remove, or change components or interactions without breaking everything else

This is exactly what the Mediator Pattern is designed to solve.

2. The Mediator Pattern

The Mediator Pattern promotes loose coupling by centralizing communication between objects. Instead of having components refer to and interact with each other directly, they communicate through a mediator.

This leads to a cleaner separation of concerns and makes components easier to reuse in different contexts.

Class Diagram

Mediator Interface

Declares a method (commonly notify()componentChanged(), or send()) used by components to send events to the mediator.

ConcreteMediator

Implements the mediator interface and coordinates communication between registered components. It holds references to all components it manages.

Component Base Class (optional)

An abstract class or interface for UI elements or modules. It holds a reference to the mediator and delegates communication through it.

ConcreteComponents

These are the actual components (e.g., TextFieldButtonLabel) that perform actions and notify the mediator when changes occur. They never talk directly to each other.

3. Implementing Mediator

Let’s refactor our tightly coupled login form using the Mediator Pattern. Each UI component will interact only with the mediator, which will handle all coordination and logic.

1. Define the UIMediator Interface

This interface defines how components will notify the mediator when their state changes. It provides a method like componentChanged() to centralize communication.

2. Define the Abstract Component (UIComponent)

This abstract base class holds a reference to the mediator and provides a method to notify it when something changes. All UI elements will extend this class.

This ensures a consistent way for all components to communicate with the mediator.

3. Implement the Components

Each component (e.g., TextFieldButtonLabel) extends UIComponent and defines its own local behavior. These components no longer interact with each other directly — they only notify the mediator.

🖊️ TextField

🔘 Button

🏷️ Label

4. Implement the Concrete Mediator (FormMediator)

This class knows about all components and defines the rules for how they should behave in response to one another. When a component changes, the mediator coordinates the appropriate actions.

5. Connect Everything in the Client

Now, the client wires everything together — components are instantiated, linked to the mediator, and can be used without knowing about each other.

Output

What We Achieved

  • Loose coupling: Components no longer know about each other
  • Separation of concerns: Coordination logic lives in the mediator, not in the components
  • Ease of extension: Add new components or behaviors without modifying existing ones
  • Reusability: Components like TextFieldButton, and Label can be reused in other contexts