The Mediator Pattern In C# .NET – Part 1 – What’s A Mediator?

This is part 1 of a series on using the Mediator Pattern in C# .NET. It’s a pretty good place to get started!


The Mediator Pattern In C# .NET

Part 1 – What’s A Mediator?
Part 2 – Roll Your Own
Part 3 – MediatR


A couple of years back, I had to help out on a project that was built entirely using the “Mediator Pattern”. Or more specifically, built entirely using the MediatR library. There were all these presentations about the “theory” behind the Mediator Pattern and how it was a real new way of thinking. I couldn’t help but think… We’ve been doing this for years. Except we just call it good programming… Infact I had my own pattern which we’ll look into in Part 2 that I called the “IEnumerable Pattern” which achieved the same thing.

But it’s taken all these years to finally write it all down. So here it is. Here’s the Mediator Pattern in C# .NET

The Mediator Pattern “Definition”

The Mediator Pattern actually dates all the way back to 1994 in the famous book “Design Patterns: Elements of Reusable Object-Oriented Software”. But I feel like it’s only really sprung up again lately due to a slew of libraries trying to implement the pattern.

In a nutshell, the definition (as stolen from Wikipedia) is :

The essence of the Mediator Pattern is to “define an object that encapsulates how a set of objects interact”. It promotes loose coupling by keeping objects from referring to each other explicitly, and it allows their interaction to be varied independently. Client classes can use the mediator to send messages to other clients, and can receive messages from other clients via an event on the mediator class.

So let’s break it down a little into two bullet points that we will refer back to later.

  • It’s an object that encapsulates how objects interact. So it can obviously handle passing on “messages” between objects.
  • It promotes loose coupling by not having objects refer to each other, but instead to the mediator. So they pass the messages to the mediator, who will pass it on to the right person.

That’s honestly it.

And when you think about just those two bullet points in isolation. It sounds awfully like a message hub of sorts right? That’s because… It actually kinda is. It’s like a message hub in code. When you send a message through a typical message hub, you don’t know who is receiving that message, you just know that the hub knows and it will sort it out for you.

In Visual Form

If we break this out into visual form using my (very limited) lucidchart skills. It looks a bit like this :

This is probably a simplified version of it because a Mediator Pattern does allow two way communication, it’s not just a one way broadcast, but I think this is the model we are going to try and use going forward in our examples.

Again, looking at it this way, it’s hard not to see the comparisons to messaging systems. But on the other hand, it’s hard not to also feel like this could very quickly turn into one of those “super” classes where sure, MyService doesn’t reference every handler… But the Mediator does. But there are ways to handle that which we will go into later.

Why?

And finally, the “Why?”. Why is this even a thing?

Well if we take the diagram above, if we had MyService calling other handlers directly (For example notifying them about an action), then as we add handlers, MyService has to start referencing them all even if it doesn’t care about the result. For example, our service might start looking like this :

class MyService
{
    private readonly Handler1 _handler1;
    private readonly Handler2 _handler2;
    private readonly Handler3 _handler3;
            

    public MyService(Handler1 handler1, Handler2 handler2, Handler3 handler3)
    {
        _handler1 = handler1;
        _handler2 = handler2;
        _handler3 = handler3;
    }

    public void DoSomething()
    {
        //Do something here. 
        //And do some more work

        //And then notify our handlers. 
        _handler1.Notify(new HandlerArgs());
        _handler2.Notify(new HandlerArgs());
        _handler3.Notify(new HandlerArgs());
    }
}

So what happens when we add more handlers? Or remove handlers? Our service keeps changing when in reality it doesn’t really care who gets notified.

Using a Mediator Pattern, it may instead end up looking like :

class MyService
{
    private HandlerMediator _handlerMediator;

    public MyService(HandlerMediator handlerMediator)
    {
        _handlerMediator = handlerMediator;
    }

    public void DoSomething()
    {
        //Do something here. 
        //And do some more work

        //And then notify our handlers. 
        _handlerMediator.Notify(new HandlerArgs());
    }
}


class HandlerMediator
{
    private readonly Handler1 _handler1;
    private readonly Handler2 _handler2;
    private readonly Handler3 _handler3;


    public HandlerMediator(Handler1 handler1, Handler2 handler2, Handler3 handler3)
    {
        _handler1 = handler1;
        _handler2 = handler2;
        _handler3 = handler3;
    }

    public void Notify(HandlerArgs handlerArgs)
    {
        _handler1.Notify(handlerArgs);
        _handler2.Notify(handlerArgs);
        _handler3.Notify(handlerArgs);
    }
}

So there’s the bonus that as handlers change, get added or removed, the service itself doesn’t change. But there is also a bit of a downer that we are maybe shifting the load to the Mediator, it’s job is now to manage the handlers and how they get notified. But this makes sense right! To have a class whose sole job is to notify clients should be able to change depending on how those clients need to be notified. And our service which really doesn’t care about the implementation details of those handlers can get on with it’s work.

In saying that, later on we will see how we use DI to really help us ease the load from both classes and yet still stick to heart of the Mediator Pattern.

What’s Next?

In the next article in this series, we are going to look at a pattern that I dubbed the “IEnumerable” pattern. It’s essentially the Mediator Pattern with some dependency injection thrown in! You can check out that article here!

8 thoughts on “The Mediator Pattern In C# .NET – Part 1 – What’s A Mediator?”

  1. “I couldn’t help but think… We’ve been doing this for years. Except we just call it good programming… ”
    It is comments like this that I’m missing more and more in the recent years. People are so “buzz-word” oriented recently that they miss the point. I see more and more the abuse of trendy practices just for the sake of using them…

    Reply
  2. Yeah, we can keep adding those layers and moving code around. It only makes it more convoluted and obscure.
    The only moment I can think of when this pattern would be useful is when there are _multiple_ services accessing the handlers. Otherwise it’s the violation of KISS and YAGNI.

    Reply
  3. Consider 3 classes O1, O2 and M. Assume M is the mediator, mediating between O1 and O2.

    Now, let’s put them in the context of the two points in your definition:

    1) The mediator M is an object that encapsulates how O1 and O2 interact. So it can obviously handle passing on “messages” between O1 and O2.
    2) M promotes loose coupling by not having O1 and O2 refer to each other, but instead to the mediator M. So they pass the messages to M, who will pass it on to the right person.

    Who then controls the interation between M and O1 and between M and O2? How can you say you promote loose coupling when you infact couple M and O1 as well as M and O2?

    Reply
    • Good question. The answer is if you are going

      O1 -> M -> 02

      There likely isn’t such a need for a mediator because it’s a “one to one” relationship. But consider this.

      I have a set of 3 handlers, let’s call them H1, H2, H3. And I have a set of 3 services, let’s call them S1,S2,S3. All 3 handlers should always be all run together. All 3 services have a need to call all 3 handlers.

      That means for S1, it needs to reference H1, H2 and H3, and call them in order. S2 and S3 also need to have a direct reference to these handlers. If you add another handler, you then need to go back and add an H4 to S1, S2 and S3.

      Instead if we plonk a “mediator” in the middle. S1, S2, S3 all reference M. They will forever reference M and only M even if we add or remove additional handlers. Adding a handler *does* require us to add a new reference to M, but it’s only in a single place, Whereas before we are having to add references to 2 different classes.

      It’s loose coupling between S1, S2, S3 and H1, H2, H3. But it is “strong” coupling to the mediator. I understand that you are swapping one strong couple for another, but you are coupling “less”.

      Hopefully that makes sense!

      Reply
    • I disagree slightly, although they are very similar patterns.

      A facade I generally think of as a “service” that combines multiple different smaller pieces, but presents them in a more coherent and simplified way. But when you call the facade, and then the facade calls it’s pieces,, it’s all tightly coupled (There are direct references to everything). It’s probably more like the first example in the post. It’s also more of a structural pattern.

      Whereas a mediator is mostly about how objects interact, specifically that they should be loosely coupled. And the mediator should handle any conversations required between them (For example using Mediatr). It’s more behavioural.

      But feel free to comment with your own interpretation 🙂

      Reply

Leave a Comment