Mediator Pattern in C#

Introduction:
The Mediator pattern is a behavioral design pattern that promotes loose coupling between communicating components. It encapsulates the communication logic between objects within a mediator object, reducing dependencies and making the code easier to maintain and extend. In this article, we will explore how to implement the Mediator pattern in C# with a real-world example.

What is the Mediator Pattern?
The Mediator pattern defines an object that encapsulates how a set of objects interact with each other. It acts as a central hub, enabling communication between objects without them having explicit knowledge of each other. Instead of objects directly communicating with each other, they send messages or notifications to the mediator, which then distributes the information to the relevant components.

Example Scenario:
Suppose we have a chat application where users can send messages to each other. To keep the code flexible and maintainable, we can use the Mediator pattern to handle the communication between users. Let’s see how we can implement it.

Implementation:
First, we need to define the components that will be communicating through the mediator. In our case, these components are the Users. Each User will have a reference to the Mediator object. The Mediator will act as a central point for receiving and distributing messages.

public abstract class User
{
    protected Mediator mediator;
    public User(Mediator mediator)
    {
        this.mediator = mediator;
    }

    public abstract void Send(string message);
    public abstract void Receive(string message);
}

public class ConcreteUser : User
{
    public ConcreteUser(Mediator mediator) : base(mediator)
    {
    }

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

    public override void Receive(string message)
    {
        Console.WriteLine($"Received message: {message}");
    }
}

public abstract class Mediator
{
    public abstract void SendMessage(string message, User user);
}

public class ConcreteMediator : Mediator
{
    private List<User> users = new List<User>();

    public void AddUser(User user)
    {
        users.Add(user);
    }

    public override void SendMessage(string message, User user)
    {
        foreach (var u in users)
        {
            if (u != user)
            {
                u.Receive(message);
            }
        }
    }
}

In the above code, we have an abstract User class that defines the send and receive methods. Each concrete User class will implement these methods according to its specific behavior. The Mediator abstract class defines the method for sending messages, and the ConcreteMediator class maintains a list of users and distributes messages to all users except the sender.

Usage:

var mediator = new ConcreteMediator();

var user1 = new ConcreteUser(mediator);
var user2 = new ConcreteUser(mediator);
var user3 = new ConcreteUser(mediator);

mediator.AddUser(user1);
mediator.AddUser(user2);
mediator.AddUser(user3);

user1.Send("Hello, World!");

In the above code, we create a mediator object and three users. We add the users to the mediator, and then user1 sends a message. The mediator distributes the message to all other users, and they receive it.

Conclusion:
The Mediator pattern is a powerful tool for decoupling components and facilitating communication between them. By using a mediator object, we can simplify the interactions between objects and promote better code maintainability and extensibility. In this article, we learned how to implement the Mediator pattern in C# with a chat application example.