Mediator Design Pattern in C#

Mediator Design Pattern in C# with Real-Time Examples

In this article, I am going to discuss the Mediator Design Pattern in C# with Real-Time Examples. Please read our previous article where we discussed the Interpreter Design Pattern in C# with Examples. The Mediator Design Pattern falls under the category of Behavioral Design Pattern. As part of this article, we are going to discuss the following pointers in detail.

  1. What is the Mediator Design Pattern?
  2. Why do we need the Mediator Design Pattern?
  3. Understanding the Class or UML Diagram of Mediator Design Pattern
  4. Real-Time Example of Mediator Design Pattern – Facebook Group
  5. Implementing the Mediator Pattern in C#
What is the Mediator Design Pattern?

According to the Gang of Four definitions, define an object that encapsulates how a set of objects interact with each other. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

Let us first simplify the above definitions. The Mediator Design Pattern is used to reduce the communication complexity between multiple objects. This design pattern provides a mediator object and that mediator object will take the responsibility to handle all the communication complexities between different objects.

The Mediator object acts as the communication center for all objects. That means when an object needs to communicate with another object, then it does not call the other object directly, instead, it calls the mediator object and it is the responsibility of the mediator object to route the message to the destination object.

Example to Understand Mediator Design Pattern:

Let us understand Mediator Design Pattern in C# with an Example. Please have a look at the following diagram. As you can see in the below diagram, we have four objects (Object A, Object B, Object C, and Object D). And these four objects want to communicate with each other. Suppose, Object A wants to communicate with Object B, then Object A should know the reference of Object B, and using that reference Object A can call the method of Object B. Similarly if Object B wants to send some message to Object C, then it should know the reference of Object C and using that reference it will call the methods of Object C and sends the message.

Why do we need the Mediator Design Pattern?

The couplings between the objects are more i.e. tight coupling. A lot of object knows each other. Now in the above image, four objects are there. In real-time, you may have thousands of objects, and those thousands of objects want to communicate with each other. Then writing code and maintaining code is very difficult.

How do we Reduce the Coupling between the Objects?

Using Mediator Design Pattern we can reduce the coupling between objects. To understand this, please have a look at the following diagram. As you can see in the below image, here we introduce the Mediator object. Each object has to send messages to the mediator object. What the mediator object do here is, it will receive the message from each object and route that message to the destination object. So, the mediator object will take care of handling the messages. So, in this type of scenario, we can use the Mediator Design Pattern

What is the Mediator Design Pattern in C#?

Real-Time Example to Understand Mediator Design Pattern – Facebook Group

Please have a look at the following diagram. Nowadays, everybody is aware of Facebook. On Facebook, we can create some specific groups and in that groups, people can join and share their knowledge. Assume on Facebook there is a group called Dot Net Tutorials and in that group, many peoples (such as Ram, Sam, Pam, Dave, Steve, Anurag, etc.) are joined. Let’s say Ram sharing some messages in the Dot Net Tutorials group. Then what this Facebook Group (Dot Net Tutorials) will do is it will send that message to all the members who are joined this group. So, here the Facebook group is acting as a Mediator.

Facebook Group

Implementing Mediator Design Pattern Real-Time Example in C#:

Let us first implement the above Facebook Example using the Mediator Design Pattern in C# step by step. And then we will understand the UML or Class Diagram of the Mediator Design Pattern by comparing it with our Example so that you can easily understand the different components involved in the Mediator Design Pattern.

Step1: Creating Mediator

This is going to be an Interface that defines operations that can be called by colleague objects for communication. So, Create an interface with the name FacebookGroupMediator.cs and then copy and paste the following code into it. This interface declares two abstract methods (i.e. SendMessage and RegisterUser).

namespace MediatorDesignPattern
{
    //Mediator Interface
    //This is going to be an Interface that defines operations 
    //which can be called by colleague objects for communication.
    public interface IFacebookGroupMediator
    {
        //This Method is used to send the Message who are registered with the Facebook Group
        void SendMessage(string msg, User user);
        //This method is used to register a user with the Facebook Group
        void RegisterUser(User user);
    }
}
Step2: Creating ConcreteMediator

This is going to be a class implementing the communication operations of the Mediator Interface. So, Create a class file with the name ConcreteFacebookGroupMediator.cs and then copy and paste the following code into it. This class implements the FacebookGroupMediator interface and provides implementations for the SendMessage and RegisterUser abstract methods. The RegisterUser method will add the user to the particular Facebook group i.e. adding the user to the UsersList variable. On the other hand, whenever any user shares any message in the group, then the SendMessage method will receive that message and it will send that message to all the users who are registered in the group except the user who shares the message. The following example code is self-explained, so please go through the comment lines for a better understanding.

using System.Collections.Generic;
namespace MediatorDesignPattern
{
    // Concrete Mediator
    // This is going to be a class implementing the communication operations of the Mediator Interface.
    public class ConcreteFacebookGroupMediator : IFacebookGroupMediator
    {
        //The following variable is going to hold the list of objects to whom we want to communicate
        private List<User> UsersList = new List<User>();

        //The following method simply registers the user with Mediator
        public void RegisterUser(User user)
        {
            //Adding the user
            UsersList.Add(user);
            //Registering the user with Mediator
            user.Mediator = this;
        }

        //The following method is going to send the message in the group i.e. to the group users
        public void SendMessage(string message, User user)
        {
            foreach (User u in UsersList)
            {
                //Message should not be received by the user sending it
                if (u != user)
                {
                    u.Receive(message);
                }
            }
        }
    }
}
Step 3: Creating the Colleague

This is going to be an abstract class that defines a property that holds a reference to a mediator. So, create an abstract class with the name User.cs and then copy and paste the following code into it. This abstract class has two abstract methods i.e. Send and Receive. The following class code is self-explained, so please go through the comment lines for a better understanding.

namespace MediatorDesignPattern
{
    // Colleague
    // This is going to be an abstract class that defines a property that holds a reference to a mediator.    
    public abstract class User
    {
        //This Property holds the name of the user
        protected string Name;

        //This Property is going to set and get the Mediator Instance
        //This Property value is going to be set when we register a user with the Mediator
        public IFacebookGroupMediator Mediator { get; set; }
        
        //Initializing the name using Constructor
        public User(string name)
        {
            this.Name = name;
        }

        //The following Methods are going to be Implemented by the Concrete Colleague
        public abstract void Send(string message);
        public abstract void Receive(string message);
    }
}
Step4: Creating Concrete Colleague

These are the classes that communicate with each other via the mediator. Create a class file with the name ConcreteUser.cs and then copy and paste the following code into it. This is a concrete class and this class implements the User abstract class and provides the implementation for the Send and Receive abstract methods. The Send method is basically used to send a message to a particular Facebook group. The Receive method is used to receive a message from a particular Facebook group. The following code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace MediatorDesignPattern
{
    //Concrete Colleague
    //These are the classes that communicate with each other via the mediator.
    public class ConcreteUser : User
    {
        //Parameterized Constructor is required to set the base class Name Property
        public ConcreteUser(string Name) : base(Name)
        {
        }

        //Overriding the Receive Method
        //This method is going to use by the Mediator to send the message to each member of the group
        public override void Receive(string message)
        {
            Console.WriteLine(this.Name + ": Received Message:" + message);
        }

        //This method is used to send the message to the Mediator by a user
        public override void Send(string message)
        {
            Console.WriteLine(this.Name + ": Sending Message=" + message + "\n");
            Mediator.SendMessage(message, this);
        }
    }
}
Step5: Client

The Main method of the Program class is going to be the client. So, please modify the Main method of the Program class as shown below. Here, first, we create the FacebookGroupMediator object, then we are creating several Facebook users, and then we are registering all the users to the mediator object. Then using the Dave and Rajesh user, we are sending a message to the Mediator. The following client code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace MediatorDesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            //Create an Instance of Mediator i.e. Creating a Facebook Group
            IFacebookGroupMediator facebookMediator = new ConcreteFacebookGroupMediator();

            //Create instances of Colleague i.e. Creating users
            User Ram = new ConcreteUser("Ram");
            User Dave = new ConcreteUser("Dave");
            User Smith = new ConcreteUser("Smith");
            User Rajesh = new ConcreteUser("Rajesh");
            User Sam = new ConcreteUser("Sam");
            User Pam = new ConcreteUser("Pam");
            User Anurag = new ConcreteUser("Anurag");
            User John = new ConcreteUser("John");

            //Registering the users with the Mediator i.e. Facebook Group
            facebookMediator.RegisterUser(Ram);
            facebookMediator.RegisterUser(Dave);
            facebookMediator.RegisterUser(Smith);
            facebookMediator.RegisterUser(Rajesh);
            facebookMediator.RegisterUser(Sam);
            facebookMediator.RegisterUser(Pam);
            facebookMediator.RegisterUser(Anurag);
            facebookMediator.RegisterUser(John);

            //One of the users Sending one Message in the Facebook Group
            Dave.Send("dotnettutorials.net - this website is very good to learn Design Pattern");
            Console.WriteLine();

            //Another user Sending another Message in the Facebook Group
            Rajesh.Send("What is Design Patterns? Please explain ");

            Console.Read();
        }
    }
}
Output:

Mediator Design Pattern in C# with Examples

Understanding the Class or UML Diagram of Mediator Design Pattern in C#:

Let us understand the Class Diagram or UML Diagram of the Mediator Design Pattern in C# and understand the different components involved. Please have a look at the following image.

Class or UML Diagram of Mediator Design Pattern

As shown in the above UML or Class Diagram, there are four participants involved in the Mediator Design Pattern in C#. Their role and responsibility are as follows:

  1. Mediator:  This is going to be an Interface that defines the operations which can be called by colleague objects for communication. In our example, it is the IFacebookGroupMediator Interface.
  2. ConcreteMediator:  This is going to be a class implementing the communication operations of the Mediator Interface. In our example, it is the ConcreteFacebookGroupMediator class.
  3. Colleague: It is an abstract class and this abstract class is going to be implemented by Concrete Colleague classes. In our example, it is the User abstract class.
  4. ConcreteColleage1 / ConcreteColleage2: These are classes that implement the Colleague interface. If a concrete colleague (let’s say ConcreteColleage1) wants to communicate with another concrete colleague (let’s say ConcreteColleage2), they will not communicate directly instead they will communicate via the ConcreteMediator. In our example, it is the ConcreteUser class.
Real-Time Example of Mediator Design Pattern – ATC

ATC stands for Air Traffic Control. The ATC mediator is nothing but the Air Traffic Control Tower which is available at the Airport. Please have a look at the following image. Here, you can see different flights (such as Flight 101, Flight 202, Flight 707, and Flight 808).

Suppose Flight 101 wants to land at a particular terminal in the Airport. Then the Flight Pilot will do is he will communicate with the ATC Mediator and says he wants to land Flight 101 at the particular airport terminal. Then the ATC Mediator will do is, he will check whether any flight is there at that particular terminal or not. If no flight is there, then what the ATC mediator will do is it will send a message to Pilots of other flights saying that Flight 101 is going to land and you should not land at that particular terminal. Then the ATC mediator sends a message to the Flight 101 pilot, saying you can land your flight at the particular airport terminal. Once the Flight 101 pilot got the confirmation message from the ATC Mediator then he will land the flight at that particular terminal.

Air Traffic Control Tower

So, here the ATC mediator will act as a central point and all flights should communicate with the ATC mediator. So, what the ATC mediator will do is, it will receive the message and route the message to the appropriate destinations. Here destinations are flights.

Note: The pilots of the planes that are approaching or departing the terminal area communicate with the tower rather than explicitly communicating with one another. The constraints on who can take off or land are enforced by the tower. It is important to note that the tower does not control the whole flight. It exists only to enforce constraints in the terminal area.

When to use Mediator Design Pattern in Real-Time Applications?

We need to use the Mediator Design Pattern in Real-Time Applications when

  1. We want communication between multiple objects to be well-defined but potentially complex.
  2. We have too many relationships that exist and a common point of control or communication is required.

In the next article, I am going to discuss the Memento Design Pattern in C# with Examples. Here, in this article, I try to explain the Mediator Design Pattern in C# with Real-Time Examples. I hope now you understood the need and use of the Mediator Design Pattern in C# with Real-Time Examples.

Leave a Reply

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