Mediator Pattern in C#
Tags: beginners, programming, tutorial, csharp
Published: 2022-09-11 18:51:28

_Originally posted [here](https://dfordebugging.wordpress.com/2022/09/11/mediator-pattern-in-c/)_

The **Mediator** is a behavioural design pattern that lets us reduce chaotic dependencies between objects. The pattern restricts direct communications between the entities and forces them to collaborate only via a mediator object.

You can find the example code of this post, on [GitHub](https://github.com/Kalkwst/DesignPatterns)

## Conceptualizing the Problem
Let's say we have a user interface dialogue for creating and editing a customer profile. It consists of various form controls such as text fields, checkboxes, buttons, tabs, etc.

![Pre-Mediator Spagghetti](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kru1j6oiz3zrg9xk1am9.PNG)

Some of the form elements may interact with others. For instance, selecting the "I have a roommate" checkbox may reveal a hidden text field for entering the roommate's name. Another example is the submit button that triggers the validation of values of all fields before submitting the data.

By having this logic implemented directly by the form elements, we make these elements much harder to reuse in other parts of the application. For example, we won't be able to use that checkbox on another form, since it's coupled to the roommate's text field. We can either use all the classes involved in rendering on the profile form, or none at all.

The **Mediator** pattern suggests that we should cease all direct communication between the components that should be independent of each other. Instead, these components must communicate indirectly, by calling a special *mediator* object. This mediator object will redirect the calls to the appropriate components. As a result, the components only depend on a single mediator class instead of being coupled to each other.

In our example, the dialogue class may act as the mediator. Most likely, the dialogue class is already aware of all of its sub-elements, so we won't even need to introduce new dependencies into this class.

![Mediator Dependencies](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lu11fcz7jwpt6thc6dgr.PNG)

The most significant change happens to the actual form elements. Consider the submit button. With the previous implementation, each time a user clicked the button, it had to validate the values of every form element. Now its single job is to notify the dialogue about the click. Upon receiving this notification, the dialogue itself performs the validation or passes the task to the individual elements. Thus instead of being coupled with dozens of elements, the button is only dependent on the dialogue class.

We can make the dependency even looser by extracting the common interface for all types of dialogues. The interface would declare the notification method that all form elements can use to notify the dialogue about events triggered by those elements. Thus, our submit button should now be able to work with any dialogue that implements that interface.

This way, the Mediator pattern lets us encapsulate a complex web of relations between various objects inside a single mediator object. The fewer dependencies a class has, the easier it becomes to modify, extend or reuse that class.

## Structuring the Mediator Pattern

In its base implementation, the Mediator pattern has three participants:

![Mediator Class Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7imqvm03wlh3yuqtwpnw.PNG)

- **Component**: The **Components** are various classes that contain some business logic. Each component has a reference to a mediator, declared through the mediator interface. The component isn't aware of the actual class of the mediator, so we can reuse the component by linking it to a different mediator. Components must not be aware of other components. If something important happens within or to a component, it must notify the mediator. When the mediator receives the notification, it can identify the sender, which is enough to decide what component should be triggered. 
- **Mediator**: The **Mediator** interface declares methods of communication with components, which most of the time include just a single notification method. Components may pass any context as arguments of this method, including their objects, but only in such a way that no coupling can occur.
- **Concrete Mediator**: The **Concrete Mediators** encapsulate relations between various components. Concrete mediators often keep references to all components they manage and sometimes even manage their lifecycles.

To demonstrate how the **Mediator** pattern works, we are going to model the snack bars in big amusement parks.

Amusement parks usually have a somewhat centralized food court with some snack bars and several smaller establishments peppered around, for gluttonous patrons to order salty snacks and sugary drinks to their increasingly-stressed heart's content.

But selling snacks to hungry hungry patrons requires supplies, and sometimes the different snack bars might run out of them. Let's imagine a system in which the different concession stands can talk to each other, communicating what supplies they need and who might have them. We can model this system using the **Mediator** pattern.

First, we'll need a **Mediator** interface, which defines a method by which the snack bars can talk to each other:

```csharp
using Mediator.Components;

namespace Mediator
{
    /// <summary>
    /// The Mediator interface, which defines a send message
    /// method which the concrete mediators must implement.
    /// </summary>
    public interface IMediator
    {
        public void SendMessage(string message, SnackBar snackBar);
    }
}
```

We also need an abstract class to represent the **Components** that will be talking to one another:

```csharp
namespace Mediator.Components
{
    /// <summary>
    /// The SnackBar abstract class represents an
    /// entity involved in the conversation which 
    /// should receive messages.
    /// </summary>
    public class SnackBar
    {
        protected IMediator _mediator;

        public SnackBar(IMediator mediator)
        {
            _mediator = mediator;
        }
    }
}
```

Now let's implement the different Components. In this case, we have two snack bars: one selling hotdogs and one selling french fries.

```csharp
namespace Mediator.Components
{
    /// <summary>
    /// A Concrete Component class
    /// </summary>
    public class HotDogStand : SnackBar
    {
        public HotDogStand(IMediator mediator) : base(mediator)
        {
        }

        public void Send(string message)
        {
            Console.WriteLine($"HotDog Stand says: {message}");
            _mediator.SendMessage(message, this);
        }

        public void Notify(string message)
        {
            Console.WriteLine($"HotDog Stand gets message: {message}");
        }
    }
}
```

```csharp
namespace Mediator.Components
{
    /// <summary>
    /// A Concrete Component class
    /// </summary>
    public class FrenchFriesStand : SnackBar
    {
        public FrenchFriesStand(IMediator mediator) : base(mediator)
        {
        }

        public void Send(string message)
        {
            Console.WriteLine($"French Fries Stand says: {message}");
            _mediator.SendMessage(message, this);
        }

        public void Notify(string message)
        {
            Console.WriteLine($"French Fries Stand gets message: {message}");
        }
    }
}
```

Note that each Component must be aware of the Mediator that is mediating the snack bar's messages.

Finally, we can implement the **ConcreteMediator** class, which will keep a reference to each Component and manage communication between them.

```csharp
using Mediator.Components;

namespace Mediator
{
    /// <summary>
    /// The Concrete Mediator class, which implements the send message
    /// method and keep track of all participants in the conversation.
    /// </summary>
    public class SnackBarMediator : IMediator
    {
        private HotDogStand hotDogStand;
        private FrenchFriesStand friesStand;

        public HotDogStand HotDogStand { set { hotDogStand = value; } }
        public FrenchFriesStand FriesStand { set { friesStand = value; } }

        public void SendMessage(string message, SnackBar snackBar)
        {
            if (snackBar == hotDogStand)
                friesStand.Notify(message);
            if (snackBar == friesStand)
                hotDogStand.Notify(message);
        }
    }
}
```

In our `Main()` method, we can use our Mediator to simulate a conversation between two snack bars. Suppose that one of the snack bars has run out of cooking oil and needs to know if the other has extra that they're not using:

```csharp
using Mediator;
using Mediator.Components;

SnackBarMediator mediator = new SnackBarMediator();

HotDogStand leftKitchen = new HotDogStand(mediator);
FrenchFriesStand rightKitchen = new FrenchFriesStand(mediator);

mediator.HotDogStand = leftKitchen;
mediator.FriesStand = rightKitchen;

leftKitchen.Send("Can you send more cooking oil?");
rightKitchen.Send("Sure thing, Homer's on his way");

rightKitchen.Send("Do you have any extra soda? We've had a rush on them over here.");
leftKitchen.Send("Just a couple, we'll send Homer back with them");

Console.ReadKey();
```

If we run this application, we'll see a conversation between the two snack stands:

![Mediator Example Output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zgvph2z39oefht88aeib.PNG)

## The MediatR Library
The [MediatR](https://github.com/jbogard/MediatR) library describes itself as a *Simple mediator implementation in .NET*. MediatR is essentially a library that facilitates in-process messaging.

### Installing MediatR
First, we need to install the MediatR NuGet package. So from our package manager console, we can run:

```powershell
Install-Package MediatR
```

We'll also need a package of extensions that allows us to use the .NET Core in-built IoC container.

```powershell
Install-Package MediatR.Extensions.Microsoft.DependencyInjection
```

Next, we need to setup our **MediatR** dependencies:

```csharp
private static IMediator BuildMediator(WrappingWriter writer)
{
    var services = new ServiceCollection();

    services.AddSingleton<TextWriter>(writer);
    services.AddMediatR(typeof(Ping));

    var provider = services.BuildServiceProvider();

    return provider.GetRequiredService<IMediator>();
}
```

### Creating our Handlers
MediatR has two messaging types. We can use either *send and receive* messaging or *broadcast* messaging. In this example, we are going to simulate a very simple health check system, where the client *pings* a server, and if the server is up and running will *pong* the client.

First, we are going to implement a simple `Ping` class that will implement the `IRequest` interface.

```csharp
namespace MediatRExample
{
    public class Ping : IRequest<string>
    {
        public string Message { get; set; }
    }
}
```

Next, we need a handler for the message. To do that we just need to implement the `IRequestHandler` interface.

```csharp
namespace MediatRExample
{
    public class PingHandler : IRequestHandler<Ping, string>
    {
        public Task<string> Handle(Ping request, CancellationToken cancellationToken)
        {
            return Task.FromResult("Pong");
        }
    }
}
```

### Using our Mediator Service
Finally, we are going to create a runner class that will call our Mediator service. The method starts by using the writer instance to write the text "Sending Ping..." to the output stream. Then, it calls the Send method of the mediator instance and passes a new instance of the Ping class with the message "Ping" The Send method sends the Ping message to the Handler that should handle it, and then returns the answer:

```csharp
using MediatR;

namespace MediatRExample
{
    public static class Runner
    {
        public static async Task Run(IMediator mediator, WrappingWriter writer)
        {
            await writer.WriteLineAsync("Sending Ping...");
            var pong = await mediator.Send(new Ping { Message = "Ping" });
            await writer.WriteLineAsync("Received: " + pong);
            await writer.WriteLineAsync();
        }
    }
}
```

Finally, we need our main method to run everything.

The `BuildMediator` method makes a new `ServiceCollection` object and adds the `TextWriter` object and the `MediatR` library to it. Then, it makes a new `ServiceProvider` instance and retrieves the `IMediator` instance from the provider.

At the start of the `Main` method, a new instance of the `WrappingWriter` class is created. This class wraps the `Console.Out` stream. Then, it calls the `BuildMediator` method and gives the writer instance as an argument to make a new `IMediator` instance.

Finally, the `Main` method calls the `Runner.Run` method, passing in the `IMediator` instance and the writer instance, to run the `Ping` message through the mediator and write the result to the output stream.

```csharp
using MediatR;

namespace MediatRExample
{
    public static class Program
    {
        public static Task Main(string[] args)
        {
            var writer = new WrappingWriter(Console.Out);
            var mediator = BuildMediator(writer);
            return Runner.Run(mediator, writer);
        }

        private static IMediator BuildMediator(WrappingWriter writer)
        {
            var services = new ServiceCollection();

            services.AddSingleton<TextWriter>(writer);
            services.AddMediatR(typeof(Ping));

            var provider = services.BuildServiceProvider();

            return provider.GetRequiredService<IMediator>();
        }
    }
}
```

Running all of this and opening our debug console, we will get the following:

![MediatR Example Output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6n1d9v8o4mdddt3d0fok.PNG)

## Difference Between Mediator and Observer

The difference between the **Mediator** and the **Observer** pattern is often elusive. In most cases, we can implement either of these patterns; but there are cases where we can implement both.

The primary goal of the *Mediator* is to eliminate dependencies among a set of components. These components instead become dependent on a single mediator object. The primary goal of the *Observer*, on the other hand, is to establish dynamic one-way connections between objects, where some objects act as subordinates of others.

One popular implementation of the _Mediator_ pattern relies on the _Observer_ pattern. The mediator plays the role of the **publisher** and the components act as **subscribers** to the mediator events. When the _Mediator_ is implemented this way, it looks very similar to the _Observer_ pattern.

When you are confused about whether you have a *Mediator* or an *Observer* remember that the *Mediator* can be implemented differently. For example, you can permanently link all components to the same mediator object. This implementation won't resemble the *Observer* pattern but will still be an instance of the *Mediator* pattern.

Now if you have a program where all components are publishers, allowing dynamic connections between each other, you have a distributed set of *Observers*, since there is no centralized *Mediator* object.

## Pros and Cons of Mediator Pattern
|||
|:--|:--|
|✔ We can extract the communications between various components into a single place, making it easier to comprehend and maintain, thus satisfying the *Single Responsibility Principle*|❌ Over time the mediator can evolve into a **God Object**|
|✔ We can introduce new mediators without having to change the actual components.|❌ It can introduce a single point of failure. There could be a performance hit as all modules communicate indirectly.|
|✔ We can reduce coupling between components||
|✔ We can reuse individual components more easily. ||

## Relations with Other Patterns
- **Chain of Responsibility**, **Command**, **Mediator** and **Observer** are patterns that address various ways of connecting senders and receivers of requests.
	- The *Chain of Responsibility* pattern passes a request sequentially along a dynamic chain of receivers until one of them handles it
	- The *Command* pattern establishes unidirectional communication channels between senders and receivers
	- The *Mediator* pattern eliminates direct connections between senders and receivers, forcing them to communicate indirectly via the mediator object.
	- The *Observer* pattern lets receivers dynamically subscribe to and unsubscribe from receiving requests.

## Final Thoughts

In this article, we have discussed what is the Mediator pattern, when to use it and what are the pros and cons of using this design pattern. We also examined the popular [MediatR](https://github.com/jbogard/MediatR) library and how the Mediator pattern relates to other classic design patterns.

The Mediator design pattern greatly reduces coupling and improves object interaction in your software application.

It is a useful tool for solving many common software design problems. The Mediator pattern can help improve your software’s maintainability and extensibility. It decouples objects and provides a central point for interaction logic.

The Mediator design pattern is helpful in many ways and is quite flexible if appropriately used. However, it's worth noting that the Mediator pattern, along with the rest of the design patterns presented by the Gang of Four, is not a panacea or a be-all-end-all solution when designing an application. Once again it's up to the engineers to consider when to use a specific pattern. After all these patterns are useful when used as a precision tool, not a sledgehammer.