GoF - Mediator Pattern
Tags: gof, systemdesign, designpattern, beginners
Published: 2024-02-11 05:46:35

The Mediator pattern is a behavioural design pattern that promotes loose coupling between objects by encapsulating their interaction within a mediator object. It allows multiple objects to communicate with each other without needing to know each other's details, thus reducing dependencies and making the system easier to maintain and extend.

## Components of the Mediator Pattern:

**Mediator:** This is an interface or an abstract class that defines the communication protocol between colleague objects. It typically contains methods for sending messages between colleagues.
	
**Concrete Mediator:** This is the actual implementation of the mediator interface. It keeps track of colleague objects and facilitates communication between them. It acts as a central hub where objects can register and send messages.

**Colleague:** This is an interface or an abstract class that defines the behaviour of objects that interact with each other through the mediator. Colleague objects communicate with each other indirectly through the mediator.
	
**Concrete Colleague:** This is the actual implementation of the colleague interface. These are the objects that communicate with each other through the mediator. They are unaware of the existence of other colleagues and communicate solely through the mediator.

## How the Mediator Pattern Works:

**Decoupling:** The Mediator pattern promotes decoupling by ensuring that objects do not communicate directly with each other but instead communicate through the mediator. This reduces dependencies between objects, making the system more flexible and easier to maintain.

**Centralised Control:** The mediator acts as a central hub through which all communication between objects is routed. This centralised control simplifies the management of interactions between objects.

**Flexibility:** Because objects communicate through a mediator, it's easy to modify or extend the interaction between objects by simply modifying or subclassing the mediator, without needing to modify the individual colleague objects.

**Promotes Reusability:** Colleague objects can be reused in different contexts since they are not tightly coupled with each other. They can interact with different sets of colleagues by simply changing the mediator.

## Example:

**GUI Applications:** In GUI frameworks, the Mediator pattern can be used to manage interactions between different UI components such as buttons, text fields, and menus.

**Air Traffic Control System:** In an air traffic control system, the Mediator pattern can be used to coordinate communication between various components such as radar systems, flight controllers, and aircraft.

**Chat Applications:** In a chat application, the Mediator pattern can be used to manage communication between different users by routing messages through a central server.


## Sample code in Swift

```
protocol Mediator {
    func sendMessage(message: String, colleague: Colleague)
}

protocol Colleague {
    var mediator: Mediator? { get set }
    func sendMessage(message: String)
    func receiveMessage(message: String)
}

class ConcreteMediator: Mediator {
    private var colleagues = [Colleague]()
    
    func addColleague(colleague: Colleague) {
        colleague.mediator = self
        colleagues.append(colleague)
    }
    
    func sendMessage(message: String, colleague: Colleague) {
        for col in colleagues {
            if col !== colleague {
                col.receiveMessage(message: message)
            }
        }
    }
}

class ConcreteColleague1: Colleague {
    var mediator: Mediator?
    
    func sendMessage(message: String) {
        mediator?.sendMessage(message: message, colleague: self)
    }
    
    func receiveMessage(message: String) {
        print("ConcreteColleague1 received message: \(message)")
    }
}

class ConcreteColleague2: Colleague {
    var mediator: Mediator?
    
    func sendMessage(message: String) {
        mediator?.sendMessage(message: message, colleague: self)
    }
    
    func receiveMessage(message: String) {
        print("ConcreteColleague2 received message: \(message)")
    }
}

// Usage
let mediator = ConcreteMediator()
let colleague1 = ConcreteColleague1()
let colleague2 = ConcreteColleague2()

mediator.addColleague(colleague: colleague1)
mediator.addColleague(colleague: colleague2)

colleague1.sendMessage(message: "Hello from colleague1")
colleague2.sendMessage(message: "Hi from colleague2")
```

In this example, Mediator is the protocol defining the mediator interface, Colleague is the protocol defining the colleague interface, and we have concrete implementations for both ConcreteMediator and ConcreteColleague. The mediator facilitates communication between colleagues without them needing to know about each other directly.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k12jwxnr4l6ap9xec5sc.png)

## Benefits of the Mediator Pattern:

**Decouples Objects:** Objects are decoupled from each other, reducing dependencies and making the system easier to maintain and extend.

**Centralised Control:** Communication between objects is centralised, which simplifies management and coordination.

**Promotes Reusability:** Colleague objects can be reused in different contexts since they are not tightly coupled with each other.

**Simplifies Communication:** The Mediator pattern provides a simple and consistent interface for communication between objects, making the system easier to understand and reason about.

Overall, the Mediator pattern is useful in scenarios where a set of objects need to communicate with each other in a flexible and decoupled manner. It promotes better design principles such as loose coupling and separation of concerns, leading to more maintainable and scalable software systems.

[Overview of GoF Design Patterns](https://dev.to/binoy123/demystifying-gof-design-patterns-essential-techniques-for-crafting-maintainable-and-scalable-software-solutions-1dfi)