top of page

How to use the mediator design pattern in C#

Updated: May 18, 2023


Mediator Design Pattern in C#

Design patterns provide solutions to common design problems and help reduce complexity in code. One such pattern is the mediator design pattern, which promotes loose coupling and simplifies object interaction. In this article, we will explore the mediator pattern and demonstrate its implementation using C#.


Understanding the Mediator Design Pattern:

The mediator design pattern is beneficial when dealing with a large number of objects that need to communicate with each other. It introduces a mediator object that encapsulates the interactions between these objects. Instead of objects directly communicating with each other, they communicate through the mediator. This helps reduce dependencies and enhances maintainability.


In the mediator pattern, an object sends a message to the mediator when it needs to communicate with other objects. The mediator then relays the message to the appropriate receiver objects in a format they can understand. By abstracting the communication through a mediator, loose coupling is achieved, leading to more manageable code.


It's important to note that the mediator pattern differs from the facade pattern. While the mediator focuses on object interactions, the facade pattern provides a unified interface to a set of interfaces. The mediator pattern is a behavioral pattern, whereas the facade pattern is a structural pattern.


Implementing the Mediator Design Pattern in C#:

In the mediator design pattern, we have participants such as the mediator, concrete mediator, and one or more participant types (also known as colleagues).


Step 1: Define the Mediator Interface

Create an interface that defines the contract for the mediator. This interface should declare methods that allow objects to communicate with each other indirectly through the mediator. For example:

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

Step 2: Implement the Mediator

Create a concrete class that implements the mediator interface. This class will handle the communication between objects. It should maintain a list of colleagues and handle message passing between them. For example:

public class ConcreteMediator : IMediator
{
    private List<Colleague> colleagues = new List<Colleague>();

    public void AddColleague(Colleague colleague)
    {
        colleagues.Add(colleague);
    }

    public void SendMessage(string message, Colleague colleague)
    {
        foreach (var c in colleagues)
        {
            if (c != colleague)
                c.ReceiveMessage(message);
        }
    }
}

Step 3: Define the Colleague Interface

Create an interface that represents the colleagues, i.e., the objects that will communicate with each other through the mediator. This interface should declare methods for sending and receiving messages. For example:

public interface IColleague
{
    void SendMessage(string message);
    void ReceiveMessage(string message);
}

Step 4: Implement the Colleagues

Create concrete classes that implement the colleague interface. These classes will communicate with each other through the mediator. They should have a reference to the mediator and use it to send and receive messages. For example:

public class ConcreteColleagueA : IColleague
{
    private IMediator mediator;

    public ConcreteColleagueA(IMediator mediator)
    {
        this.mediator = mediator;
    }

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

    public void ReceiveMessage(string message)
    {
        Console.WriteLine("Colleague A received: " + message);
    }
}

public class ConcreteColleagueB : IColleague
{
    private IMediator mediator;

    public ConcreteColleagueB(IMediator mediator)
    {
        this.mediator = mediator;
    }

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

    public void ReceiveMessage(string message)
    {
        Console.WriteLine("Colleague B received: " + message);
    }
}

Step 5: Putting it all together

In your application, create an instance of the mediator and the colleagues. Add the colleagues to the mediator's list of colleagues. Then, the colleagues can communicate with each other indirectly through the mediator. For example:

static void Main(string[] args)
{
    var mediator = new ConcreteMediator();

    var colleagueA = new ConcreteColleagueA(mediator);
    var colleagueB = new ConcreteColleagueB(mediator);

    mediator.AddColleague(colleagueA);
    mediator.AddColleague(colleagueB);

    colleagueA.SendMessage("Hello from A");
    colleagueB.SendMessage("Hello from B");
}

When you run the application, you will see that the colleagues send messages to each other through the mediator, and the mediator relays the messages to the appropriate recipients.


That's it! You have successfully implemented the Mediator design pattern in C#. By utilizing the mediator, objects can communicate in a decoupled manner, improving maintainability and flexibility in your codebase.


Conclusion

We can achieve loose coupling and simplify object interactions in our codebase by leveraging the mediator design pattern. Through the use of a mediator object, we reduce direct dependencies between objects and improve code maintainability. Implementing the mediator pattern in C# involves defining queries, commands, and handlers, and utilizing the MediatR package. By following this approach, we can enhance the flexibility and scalability of our applications.

0 comments

Recent Posts

See All
bottom of page