Skip to content
Sentia Tech Blog
Sentia Tech Blog

  • About
  • Cloud & Infrastructure
  • Software Engineering & Development
  • AI, Data & Machine Learning
  • Cybersecurity & Digital Trust
Sentia Tech Blog

Mediator Pattern in C# with .NET Core

Alex, 1 April 20251 April 2025

The Mediator pattern provides a central point for communication between objects, simplifying interactions and reducing dependencies. In this article, the design pattern is explained with clear examples in C# using .NET Core. The article covers the concept, benefits, and implementation details, ensuring that every sentence delivers useful information for understanding the pattern.

Overview

The Mediator pattern separates the interaction logic from the individual components, resulting in a more organized and manageable codebase. Each component, or colleague, communicates with the mediator rather than with each other. This design promotes loose coupling, which leads to better testability and scalability in applications. The pattern is particularly useful in scenarios involving complex inter-object communications.

Key Benefits

Using the Mediator pattern introduces several advantages:

  • Simplified Communication: Components no longer need to keep track of each other’s states or behaviors.
  • Reduced Dependencies: The mediator acts as the central hub, ensuring that components do not depend directly on one another.
  • Improved Maintainability: Changes to the communication logic require modifications only in the mediator, keeping the colleagues unchanged.
  • Enhanced Reusability: Components become more focused on their specific roles, making them easier to reuse in different parts of the application.
  • Better Organization: With a single point of control, debugging and extending the application become more straightforward.

Implementation in .NET Core

Implementing the Mediator pattern in C# involves creating a mediator interface and concrete mediator classes. The colleagues, or components, use this mediator to interact. Below is a sample implementation to illustrate the pattern.

Mediator Interface

public interface IMediator
{
    void SendMessage(string message, Colleague colleague);
}

The interface defines a method for sending messages. The parameter allows the mediator to know the source of the message, making it possible to route communication as needed.

Concrete Mediator

public class ConcreteMediator : IMediator
{
    public Colleague1 Colleague1 { get; set; }
    public Colleague2 Colleague2 { get; set; }

    public void SendMessage(string message, Colleague colleague)
    {
        if (colleague == Colleague1)
        {
            Colleague2.ReceiveMessage(message);
        }
        else
        {
            Colleague1.ReceiveMessage(message);
        }
    }
}

This class manages the communication between two colleagues. The mediator checks the source of the message and forwards it to the appropriate recipient.

Colleague Base Class

public abstract class Colleague
{
    protected IMediator _mediator;

    protected Colleague(IMediator mediator)
    {
        _mediator = mediator;
    }
}

The base class ensures that all colleagues have a reference to the mediator. This design makes it possible to modify interactions without changing the colleague classes.

Concrete Colleagues

public class Colleague1 : Colleague
{
    public Colleague1(IMediator mediator) : base(mediator) { }

    public void Send(string message)
    {
        _mediator.SendMessage(message, this);
    }

    public void ReceiveMessage(string message)
    {
        Console.WriteLine($"Colleague1 received: {message}");
    }
}

public class Colleague2 : Colleague
{
    public Colleague2(IMediator mediator) : base(mediator) { }

    public void Send(string message)
    {
        _mediator.SendMessage(message, this);
    }

    public void ReceiveMessage(string message)
    {
        Console.WriteLine($"Colleague2 received: {message}");
    }
}

These classes demonstrate how the mediator pattern works in practice. Each colleague sends messages via the mediator and processes incoming messages through a dedicated method. This approach simplifies future modifications and potential additions of other components.

Practical Considerations

When applying the Mediator pattern in a .NET Core project, several factors must be taken into account:

  • Scalability: The mediator may become complex if the number of colleagues increases significantly. Organize the mediator to manage multiple colleagues efficiently.
  • Extensibility: Additional colleagues can be added with minimal changes to the mediator. Maintain clear separation between the mediator logic and the colleague functionalities.
  • Performance: The additional level of indirection may impact performance in high-frequency messaging systems. Evaluate the trade-offs based on project requirements.
  • Testing: The isolated nature of colleagues simplifies unit testing. Mocking the mediator allows focused tests on individual components without external dependencies.

Practical Example

Consider a chat room scenario where multiple users interact. The mediator pattern suits this design since each user sends messages through a central chat mediator. The chat mediator determines how messages are distributed to other users, minimizing direct user-to-user connections.

In this scenario, each user is a colleague that registers with the chat mediator. Upon sending a message, the mediator broadcasts it to every user except the sender. This model ensures that the communication logic remains centralized and modifications affect only the mediator.

Final Thoughts

The Mediator pattern in C# using .NET Core offers an elegant solution for managing complex communications in applications. The design minimizes direct dependencies and centralizes message handling. The sample code provides a solid foundation to implement the pattern in real-world projects, while practical considerations help address potential challenges in scalability and performance.

By adopting this pattern, developers can achieve a well-organized and flexible architecture, which ultimately simplifies long-term maintenance and future expansion of the application.

Software Engineering & Development

Post navigation

Previous post
Next post

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • CloudFront Functions vs. Lambda@Edge: What You Need to Know
  • Reducing Image File Size Using ImageProcessor in Episerver
  • Key Features of a Reliable CI/CD Pipeline Service
  • EC2 Image Builder vs. Packer: Which Tool Should You Use?
  • Building a Privacy-First Login System: OAuth, MFA & Beyond

Archives

  • May 2025
  • April 2025
  • March 2025

Categories

  • AI, Data & Machine Learning
  • Cloud & Infrastructure
  • Cybersecurity & Digital Trust
  • Software Engineering & Development
©2025 Sentia Tech Blog