Mediator Pattern in C#: Definition, Examples, Pros, Cons, and Use Cases
The Mediator pattern in C# is a behavioral design pattern that centralizes communication between objects by introducing a mediator object that coordinates their interactions.
The Mediator pattern reduces direct dependencies between objects by making them communicate through a mediator instead of referencing each other directly. This helps create loosely coupled systems where object interactions are centralized and easier to manage. Each participating object, called a colleague, sends requests to the mediator, and the mediator coordinates communication between colleagues. The mediator encapsulates interaction logic, reducing complex object relationships and improving maintainability. In C#, the Mediator pattern is commonly used in UI frameworks, messaging systems, chat applications, CQRS architectures, and workflow coordination systems.
Why We Use Mediator Pattern in C#?
We use the Mediator pattern in C# to:
• Reduce tight coupling between objects
• Centralize communication logic
• Simplify object collaboration
• Improve maintainability
• Prevent complex object dependency graphs
• Support cleaner architecture
• Simplify component reuse
• Manage communication workflows efficiently
When Should We Use Mediator Pattern in C#?
The Mediator pattern should be used when:
• Many objects communicate with each other
• Object dependencies become difficult to manage
• Communication logic is complex
• Components should remain loosely coupled
• Reusable independent components are needed
• Centralized coordination is preferred
• UI components interact heavily
Common Programming Problems Solved by Mediator Pattern
• UI component communication
• Chat room systems
• Workflow coordination
• Event orchestration
• CQRS request handling
• Air traffic control systems
• Smart home coordination
• Messaging systems
• Notification hubs
Structure of Mediator Pattern in C#
Typical participants:
• Mediator Interface
• Concrete Mediator
• Colleague Classes
• Client
Basic workflow:
• Colleague sends message to mediator
• Mediator receives request
• Mediator decides target recipients
• Mediator coordinates communication
Mediator Pattern Examples in C#
Example 1: Chat Room System
Users in a chat room should communicate without directly referencing each other.
using System;
using System.Collections.Generic;
public interface IChatMediator
{
void SendMessage(string message, User user);
void AddUser(User user);
}
public class ChatMediator : IChatMediator
{
private List<User> users = new List<User>();
public void AddUser(User user)
{
users.Add(user);
}
public void SendMessage(string message, User sender)
{
foreach (var user in users)
{
if (user != sender)
{
user.Receive(message);
}
}
}
}
public class User
{
private IChatMediator mediator;
public string Name { get; }
public User(IChatMediator mediator, string name)
{
this.mediator = mediator;
Name = name;
}
public void Send(string message)
{
Console.WriteLine($"{Name} sends: {message}");
mediator.SendMessage(message, this);
}
public void Receive(string message)
{
Console.WriteLine($"{Name} receives: {message}");
}
}
public class Program
{
public static void Main()
{
IChatMediator mediator = new ChatMediator();
User john = new User(mediator, "John");
User alice = new User(mediator, "Alice");
mediator.AddUser(john);
mediator.AddUser(alice);
john.Send("Hello Alice");
}
}
Example 2: Air Traffic Control System
Aircraft should communicate through a control tower instead of directly with each other.
using System;
public interface IControlTower
{
void SendMessage(string message, Aircraft aircraft);
}
public class ControlTower : IControlTower
{
public void SendMessage(string message, Aircraft sender)
{
Console.WriteLine($"Tower relays from {sender.Name}: {message}");
}
}
public class Aircraft
{
private IControlTower tower;
public string Name { get; }
public Aircraft(IControlTower tower, string name)
{
this.tower = tower;
Name = name;
}
public void Send(string message)
{
tower.SendMessage(message, this);
}
}
public class Program
{
public static void Main()
{
IControlTower tower = new ControlTower();
Aircraft plane1 = new Aircraft(tower, "Flight A1");
Aircraft plane2 = new Aircraft(tower, "Flight B2");
plane1.Send("Requesting landing permission");
plane2.Send("Ready for takeoff");
}
}
Example 3: Smart Home Coordination
Smart home devices should coordinate actions through a central hub.
using System;
public interface ISmartHomeMediator
{
void Notify(string eventName, Device sender);
}
public class SmartHomeHub : ISmartHomeMediator
{
public void Notify(string eventName, Device sender)
{
if (eventName == "MotionDetected")
{
Console.WriteLine("Hub turns on hallway lights");
}
}
}
public abstract class Device
{
protected ISmartHomeMediator mediator;
public Device(ISmartHomeMediator mediator)
{
this.mediator = mediator;
}
}
public class MotionSensor : Device
{
public MotionSensor(ISmartHomeMediator mediator) : base(mediator)
{
}
public void DetectMotion()
{
Console.WriteLine("Motion detected");
mediator.Notify("MotionDetected", this);
}
}
public class Program
{
public static void Main()
{
ISmartHomeMediator hub = new SmartHomeHub();
MotionSensor sensor = new MotionSensor(hub);
sensor.DetectMotion();
}
}
Most Known Real-World Use Cases in C#
• ASP.NET CQRS mediator libraries
• Chat applications
• UI dialog coordination
• Workflow orchestration
• Event aggregation systems
• Air traffic control systems
• Smart home automation
• Multiplayer game communication
• Enterprise messaging systems
Advantages of Mediator Pattern in C#
• Reduces object coupling
• Simplifies communication logic
• Centralizes interaction management
• Improves maintainability
• Enhances component reusability
• Reduces dependency complexity
• Makes systems easier to extend
• Improves code readability
Disadvantages (Weak Points) of Mediator Pattern in C#
• Mediator can become overly complex
• Centralized logic may create bottlenecks
• Large mediators may violate Single Responsibility Principle
• Adds extra abstraction layer
• Debugging communication flow can become harder
• Too many colleagues may overload mediator
• Can evolve into a “god object”
Comparison with Similar Patterns
| Pattern | Main Purpose | Communication Style | Coupling Level | Typical Usage | Main Difference from Mediator |
|---|---|---|---|---|---|
| Mediator | Centralize object communication | Through mediator | Loose | UI systems, workflows | Uses centralized coordination for communication |
| Observer | Notify subscribers | Broadcast events | Loose | Event systems | Focuses on event subscription rather than coordination |
| Facade | Simplify subsystem access | One-way interface | Moderate | API wrappers | Provides simplified access instead of coordinating peers |
| Command | Encapsulate requests | Invoker to receiver | Loose | Undo systems, queues | Encapsulates operations rather than object interactions |
| Chain of Responsibility | Pass requests through handlers | Sequential chain | Loose | Middleware pipelines | Processes requests sequentially instead of coordinating communication |
Simplified UML-Style Structure
| Component | Responsibility |
|---|---|
| Mediator Interface | Defines communication methods |
| ConcreteMediator | Coordinates colleague interactions |
| Colleague | Sends requests through mediator |
| ConcreteColleague | Implements business functionality |
| Client | Creates mediator and colleagues |
Creational Patterns in C#
13. Chain of Responsibility
14. Iterator
15. Momento
16. State
17. Template Method
18. Command
19. Mediator
20. Observer
21. Strategy
22. Visitor