The Mediator Pattern

The Mediator Pattern

Introduction

The Mediator Pattern is a valuable tool for facilitating object communication while reducing coupling and promoting loose coupling.

It promotes cleaner and more maintainable code by encapsulating communication logic in a mediator object.

Understanding the Mediator Pattern

The Mediator Pattern revolves around the concept of a mediator object that acts as an intermediary between communicating objects.

This mediator coordinates communication between the objects, eliminating direct interactions and promoting loose coupling.

Benefits of the Mediator Pattern

The Mediator Pattern offers several advantages, including:

  • Reduced Coupling: It reduces coupling between objects by encapsulating communication logic in a mediator.
  • Improved Modularity: It promotes modularity by making it easier to add or remove objects without affecting others.
  • Simplified Testing: It simplifies testing by reducing the number of direct interactions between objects.
  • Enhanced Flexibility: It enhances flexibility by allowing for easier modification of communication logic.
  • Easier to Extend: It makes it easier to extend the system by adding new mediators or communicators.

Types of Mediator Patterns

The Mediator Pattern encompasses several variations:

  • Simple Mediator: This pattern involves a single mediator object that coordinates communication between a set of objects.
  • Complex Mediator: This pattern introduces multiple mediator objects with specialised roles, handling different aspects of communication.
  • Hybrid Mediator: This pattern combines the Simple Mediator and Complex Mediator patterns, utilising a combination of mediators for different purposes.

Implementing the Mediator Pattern in C#

To illustrate the implementation of the Mediator Pattern in C#, consider a simplified scenario of managing customer orders:

Customer Interface

public interface ICustomer
{
    void PlaceOrder(Order order);
    void ReceiveOrderConfirmation(Order order);
}

Concrete Customer Classes

public class RetailCustomer : ICustomer
{
    private IMediator mediator;

    public RetailCustomer(IMediator mediator)
    {
        this.mediator = mediator;
    }

    public void PlaceOrder(Order order)
    {
        mediator.PlaceOrder(this, order);
    }

    public void ReceiveOrderConfirmation(Order order)
    {
        Console.WriteLine("Retail Customer received order confirmation: " + order.OrderId);
    }
}

public class WholesaleCustomer : ICustomer
{
    private IMediator mediator;

    public WholesaleCustomer(IMediator mediator)
    {
        this.mediator = mediator;
    }

    public void PlaceOrder(Order order)
    {
        mediator.PlaceOrder(this, order);
    }

    public void ReceiveOrderConfirmation(Order order)
    {
        Console.WriteLine("Wholesale Customer received order confirmation: " + order.OrderId);
    }
}

Mediator Class

public class OrderProcessingMediator
{
    private List<ICustomer> customers = new List<ICustomer>();

    public void AddCustomer(ICustomer customer)
    {
        customers.Add(customer);
    }

    public void PlaceOrder(ICustomer customer, Order order)
    {
        // Process the order and send confirmation to the customer
        customer.ReceiveOrderConfirmation(order);
    }
}

Using the Mediator

OrderProcessingMediator mediator = new OrderProcessingMediator();

RetailCustomer retailCustomer = new RetailCustomer(mediator);
WholesaleCustomer wholesaleCustomer = new WholesaleCustomer(mediator);

// Add customers to the mediator
mediator.AddCustomer(retailCustomer);
mediator.AddCustomer(wholesaleCustomer);

// Place orders
retailCustomer.PlaceOrder(new Order("Order 1"));
wholesaleCustomer.PlaceOrder(new Order("Order 2"));

This example demonstrates a basic implementation of the Mediator Pattern for managing customer orders.

Conclusion

The Mediator Pattern is a versatile tool for simplifying object communication and promoting loose coupling in C# applications.

By encapsulating communication logic in a mediator, it enhances code maintainability, flexibility, and testability.

Developers can leverage this pattern to create more robust and adaptable software systems.

Stephen

Hi, my name is Stephen Finchett. I have been a software engineer for over 30 years and worked on complex, business critical, multi-user systems for all of my career. For the last 15 years, I have been concentrating on web based solutions using the Microsoft Stack including ASP.Net, C#, TypeScript, SQL Server and running everything at scale within Kubernetes.