Design Patterns : Mediator Pattern

There are two reasons I thought I should be blogging about the Mediator Pattern. Firstly, I wanted to continue with the series of different design patterns and principles, filling out the missing pieces. Secondly, I would like to write a blog entry on configuring the Mediator and CQRS on a Web Api sometime soon. But at the same time, I would like to concentrate on the implementation of Web Api and hence thought about discussing the Pattern in a separate post.

Mediator

So what exactly is a Mediator Pattern. Mediator Pattern centralizes communication and control of related objects. It encapsulates how a set of objects interact with each other, without each of the objects knowing about each other.

Most often than not, partitioning system into objects usually increases the reusability of the objects. But when these objects need to interact with each other, this dependency adversely impacts the reusability factor. The mediator ensures that the earlier tightly coupled systems are no longer the same (it doesn’t even need to depend on abstractions), and rather it depends on a central mediator for communication. Each of the objects needn’t be aware of each other, but they only need to be aware of the mediator, which would act as a central hub and handle the communications.

The mediator pattern could be represented as the following.

Mediator Pattern

Let us now write some code to demonstrate the Mediator Pattern. We will begin by defining our Services/Components.

public class ServiceBase
{
    protected MediatorBase _mediator;

    public void SetMediator(MediatorBase mediator)
    {
        _mediator = mediator;
    }
}

The ServiceBase defines the component base class. It has a single method SetMediator that accepts an instance of MediatorBase (which we will get to in shortly). In the concrete implementations of ServiceBase we would be using this instance of MediatorBase to communicate with other components/services.

We will now create two concrete implementations of the ServiceBase, which would be used to demonstrate the interaction between components using a mediator.

// Service/Component A
public class ServiceA : ServiceBase
{

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

    public void DoOperationThree()
    {
        Console.WriteLine($"{nameof(ServiceA)}.{nameof(DoOperationThree)}");
    }

    public void DoOperationFour()
    {
        Console.WriteLine($"{nameof(ServiceA)}.{nameof(DoOperationFour)}");
    }
}

// Service/Component B
public class ServiceB : ServiceBase
{
    public void SendMessage(string message)
    {
        _mediator.SendMessage(message, this);
    }

    public void DoOperationOne()
    {
        Console.WriteLine($"{nameof(ServiceB)}.{nameof(DoOperationOne)}");
    }

    public void DoOperationTwo()
    {
        Console.WriteLine($"{nameof(ServiceB)}.{nameof(DoOperationTwo)}");
    }
}


If you observe the concrete implementation of ServiceBase in the above code, both of them have two methods (for convenience, named with DoOperation suffix) which do some service/component-specific operations. More importantly, it has a method(SendMessage and RaiseNotification) that communicates with the Mediator. We would be using this method to communicate with the other Component.

I have intensionally named the methods differently because of the Mediator Pattern doesn’t quite say we need to have the same signature for the communicating method/methods. In fact, the only thing it needs to do is to communicate via the mediator instance.

Let us now concentrate on defining the Mediator. The MediatorBase could be defined as the following.

public abstract class MediatorBase
{
    public abstract void SendMessage(string message, ServiceBase sender);
}

The concrete mediator could be defined as the following.

public class ConcreteMediator : MediatorBase
{
    private ServiceA _serviceA;
    private ServiceB _serviceB;

    public ConcreteMediator(ServiceA serviceA,ServiceB serviceB)
    {
        (_serviceA,_serviceB) = (serviceA,serviceB);
    }
    public override void SendMessage(string message, ServiceBase sender)
    {
        switch (sender)
        {
            case ServiceA _ :

                if(string.Equals("one", message, StringComparison.InvariantCultureIgnoreCase))
                {
                    _serviceB.DoOperationOne();
                    break;
                }
                else if (string.Equals("two", message, StringComparison.InvariantCultureIgnoreCase))
                {
                    _serviceB.DoOperationTwo();
                    break;
                }
                _serviceB.DoOperationOne();
                _serviceB.DoOperationTwo();
                break;

            case ServiceB _:

                _serviceA.DoOperationFour();
                break;
        }

    }
}

It has a constructor which accepts instances of the components involved. But do note, it is up to the discretion of the developer to design how he would like the Mediator to accept the instance of components. This is just one way.

But let us focus more on the overridden SendMessage method. This is the crux of our action. This method contains the logic of operations. Internally it uses the instance of the components/services set earlier in the constructor. The entire business logic involved in communication between the components is encapsulated within the Mediator object.

Let us now write the client code to access the component and mediators.

var serviceA = new ServiceA();
var serviceB = new ServiceB();

var mediator = new ConcreteMediator(serviceA,serviceB);

serviceA.SetMediator(mediator);
serviceB.SetMediator(mediator);

Console.WriteLine($"{nameof(ServiceA)}.One");
serviceA.RaiseNotification("One");

Console.WriteLine($"{nameof(ServiceA)}.Two");
serviceA.RaiseNotification("Two");

Console.WriteLine($"{nameof(ServiceA)}.Empty");
serviceA.RaiseNotification(String.Empty);

Console.WriteLine($"{nameof(ServiceB)}.Three");
serviceB.SendMessage("Three");

Console.WriteLine($"{nameof(ServiceB)}.Four");
serviceB.SendMessage("Four");

Console.WriteLine($"{nameof(ServiceB)}.Empty");
serviceB.SendMessage(String.Empty);

This would produce the following output.

ServiceA.One
ServiceB.DoOperationOne
ServiceA.Two
ServiceB.DoOperationTwo
ServiceA.Empty
ServiceB.DoOperationOne
ServiceB.DoOperationTwo
ServiceB.Three
ServiceA.DoOperationFour
ServiceB.Four
ServiceA.DoOperationFour
ServiceB.Empty
ServiceA.DoOperationFour

As you could see the Mediator Pattern was able to decouple the component dependency and also encapsulate the communication logic. If you are interested in the complete source code discussed in the post, you could access it on my Github.

Advertisement

3 thoughts on “Design Patterns : Mediator Pattern

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s