1. What is the Mediator Pattern
The Mediator Pattern is a behavioral design pattern that reduces the direct dependencies between objects by transferring their communication to a mediator object. In the Mediator Pattern, objects no longer communicate directly with each other, but rather through the mediator object.
2. Characteristics and Advantages of the Mediator Pattern
The characteristics and advantages of the Mediator Pattern are as follows:
- Reduces direct coupling between objects, lowering system complexity.
- Simplifies communication between objects by having a mediator object handle their communication.
- Centralizes control of interactions between objects, facilitating extension and maintenance.
3. Real-world Examples of the Mediator Pattern
The Mediator Pattern has many applications in real-life scenarios. For example, in an airport scheduling system, the dispatcher acts as the mediator, while the different modules such as airplanes and ground traffic serve as colleague classes communicate and coordinate through the dispatcher.
4. Implementation of the Mediator Pattern in Golang
4.1 Introduction to UML Class Diagram
Below is the UML class diagram for the Mediator Pattern in Golang:
4.2 Example Introduction
In this example, we will implement a simple chat room application using the Mediator Pattern to manage communication between different users.
4.3 Implementation Step 1: Define Mediator Interface and Concrete Mediator
First, we define a mediator interface and a concrete mediator class:
type Mediator interface {
registerColleague(colleague Colleague)
sendMessage(message string, colleague Colleague)
}
type ConcreteMediator struct {
colleagues map[string]Colleague
}
func (m *ConcreteMediator) registerColleague(colleague Colleague) {
m.colleagues[colleague.getName()] = colleague
}
func (m *ConcreteMediator) sendMessage(message string, colleague Colleague) {
for _, c := range m.colleagues {
if c != colleague {
c.receiveMessage(message)
}
}
}
4.4 Implementation Step 2: Define Colleague Interface and Concrete Colleague
Next, we define a colleague interface and concrete colleague classes:
type Colleague interface {
receiveMessage(message string)
sendMessage(message string)
getName() string
}
type ConcreteColleagueA struct {
mediator Mediator
name string
}
func (c *ConcreteColleagueA) receiveMessage(message string) {
fmt.Printf("%s received message: %s\n", c.name, message)
}
func (c *ConcreteColleagueA) sendMessage(message string) {
c.mediator.sendMessage(message, c)
}
func (c *ConcreteColleagueA) getName() string {
return c.name
}
type ConcreteColleagueB struct {
mediator Mediator
name string
}
func (c *ConcreteColleagueB) receiveMessage(message string) {
fmt.Printf("%s received message: %s\n", c.name, message)
}
func (c *ConcreteColleagueB) sendMessage(message string) {
c.mediator.sendMessage(message, c)
}
func (c *ConcreteColleagueB) getName() string {
return c.name
}
4.5 Implementation Step 3: Managing Colleagues in the Mediator
In the specific mediator class, we need to implement the registerColleague
method and the sendMessage
method to manage communication between colleague classes:
func main() {
mediator := &ConcreteMediator{
colleagues: make(map[string]Colleague),
}
colleagueA := &ConcreteColleagueA{
mediator: mediator,
name: "Colleague A",
}
colleagueB := &ConcreteColleagueB{
mediator: mediator,
name: "Colleague B",
}
mediator.registerColleague(colleagueA)
mediator.registerColleague(colleagueB)
colleagueA.sendMessage("Hello, World!")
colleagueB.sendMessage("Hi, there!")
}
In the main
function, we create a specific mediator object and two specific colleague objects, then register the colleague objects through the mediator object and perform communication testing.