In complex systems, objects often need to communicate with each other frequently. If objects directly reference and depend on each other, the system will become complex and difficult to maintain. In order to solve this coupling problem,Mediator PatternThe mediator pattern introduces an independent mediator object to manage the interaction between objects, thereby reducing the direct dependencies between objects and making the system more flexible. This article will introduce the concept of the mediator pattern, the difference from other similar patterns, the problems it solves, the implementation in Golang, and the precautions.
What is the Mediator pattern?
Mediator PatternIt is a behavioral design pattern.Encapsulate the interaction logic between objects through a mediator object, so that objects no longer directly reference each other, but communicate through mediators. This can reduce the coupling between objects and make the system easier to expand and maintain.
Components of the Mediator pattern
- Mediator: Defines the interface for communication between objects.
- Concrete Mediator: Implements the mediator interface, responsible for coordinating communications between objects.
- Colleague: Objects participating in the interaction, all colleague objects communicate with other objects through mediators instead of directly calling each other's methods.
Differences between the Mediator pattern and other similar patterns
The Mediator pattern has similarities with some common design patterns, but their purposes and application scenarios are different:
Observer Pattern:
- Target: The observer pattern realizes communication between objects through subscription and notification mechanisms and is suitable for one-to-many relationships.
- the difference: The observer pattern is aEvent-drivenThe mediator pattern is more suitable for managing complex interaction logic between multiple objects.
Command Pattern:
- Target: The command pattern encapsulates requests as objects to facilitate queuing, recording, and cancellation of requests.
- the difference: Command mode focuses onRequest packaging and processing, while the Mediator pattern focuses onCoordination and decoupling between objects.
Bridge Pattern:
- Target: The bridge pattern separates the abstract part from the implementation part so that they can change independently.
- the difference: The bridge pattern is used for structural decoupling, while the mediator pattern is used for behavioral decoupling.
What problem does the Mediator pattern solve?
Reduce coupling between objects: In a complex system, if objects directly reference each other, it will make the system difficult to maintain. The mediator pattern reduces the direct coupling between objects by introducing a mediator object and transferring the dependencies of each object to the mediator.
Simplify the interaction logic of objects: The mediator pattern centralizes the interaction logic between objects into a mediator, making the responsibilities of each object more single and only needing to interact with the mediator.
Improve system scalability: Since there is no direct dependency between objects, when adding new objects or modifying the interaction logic of objects, you only need to modify the mediator without affecting other objects.
Application scenarios of the mediator pattern
- Chat system: In a chat room, messages between users are passed through an intermediary (such as a server) rather than direct communication between users.
- Form component interaction: In a complex UI system, the interactions between the various components of the form (such as buttons and input boxes) can be coordinated by a mediator.
- Event System: In the event system, event transmission between different modules can be managed by mediators to avoid direct coupling between modules.
Mediator pattern implementation in Golang
Below we use a specific Golang example to show how to use the mediator pattern to implement a simple chat system.
Example: Chat Room Mediator
1. Define the mediator interface
package main // Mediator interface: defines the behavior of the mediator type Mediator interface { SendMessage(message string, sender Colleague) Register(colleague Colleague) }
2. Implementing a specific mediator
import "fmt" // ChatMediator structure: specific mediator, implements the Mediator interface type ChatMediator struct { colleagues []Colleague } func (c *ChatMediator) Register(colleague Colleague) { c.colleagues = append(c.colleagues, colleague) } func (c *ChatMediator) SendMessage(message string, sender Colleague) { for _, colleague := range c.colleagues { // Messages are not sent back to the sender if colleague != sender { colleague.Receive(message) } } }
3. Define the colleague interface
// Colleague interface: defines the behavior of colleague objects type Colleague interface { Send(message string) Receive(message string) }
4. Implement specific colleague objects
// User structure: specific colleague object, implements the Colleague interface type User struct { name string mediator Mediator } func (u *User) Send(message string) { fmt.Printf("%s sends message: %s\n", u.name, message) u.mediator.SendMessage(message, u) } func (u *User) Receive(message string) { fmt.Printf("%s receives message: %s\n", u.name, message) }
5. Sample code using the mediator pattern
func main() { // Create a specific mediator chatMediator := &ChatMediator{} // Create users (colleague objects) user1 := &User{name: "Alice", mediator: chatMediator} user2 := &User{name: "Bob", mediator: chatMediator} user3 := &User{name: "Eve", mediator: chatMediator} // Register users to the mediator chatMediator.Register(user1) chatMediator.Register(user2) chatMediator.Register(user3) // Send messages user1.Send("Hello, everyone!") user2.Send("Hi Alice!") }
Output
Alice sends message: Hello, everyone! Bob receives message: Hello, everyone! Eve receives message: Hello, everyone! Bob sends message: Hi Alice! Alice receives message: Hi Alice! Eve receives message: Hi Alice!
Code Analysis
- Mediator Interface: Defines the behavioral interface of the mediator, including methods for sending messages and registering colleague objects.
- ChatMediator Structure: Achieved
Mediator
Interface, responsible for transmitting messages between users. - Colleague Interface: Defines the behavioral interface of the colleague object, including methods for sending and receiving messages.
- User Structure: Achieved
Colleague
Interface, representing a specific user object, sends and receives messages through a mediator. - main function: Shows how to use the mediator pattern to implement a simple chat room system.
Application in actual development
The mediator pattern is widely used in actual development, especially in systems that need to manage complex interactions. The following are several common application scenarios:
- Chat system: As shown in the above example, message passing in a chat room can be achieved through a mediator.
- UI component interaction: In a complex UI system, the interactions between components can be coordinated through mediators to avoid direct dependencies between components.
- Event System: In an event-driven system, the mediator pattern can be used to manage event transmission between modules and avoid coupling between modules.
Things to note when using the mediator pattern
- Complexity of mediators:Although the mediator pattern reduces the coupling between objects, it also increases the complexity of the mediator itself. The complexity of the mediator should be controlled as much as possible during design.
- Avoid overuse: The mediator pattern is suitable for scenarios where there are complex interactions between objects. If the interactions between objects are relatively simple, using the mediator pattern may add unnecessary complexity.
- Interface design: The design of the mediator interface should be as general as possible to support different types of object interactions.
Comparison between Mediator and Observer
characteristic | Mediator Pattern | Observer Pattern |
---|---|---|
Communication | Coordinate communication between objects through a mediator | Inter-object communication through subscription-notification mechanism |
Applicable scenarios | Complex interactions between multiple objects | One-to-many event notification |
Coupling | Reduce coupling between objects | Low coupling |
Implementation complexity | May increase the complexity of the mediator | Relatively simple to implement |
Summarize
The mediator pattern introduces a mediator object to manage the interaction between objects, reducing the direct dependency between objects and making the system more flexible. In Golang, the implementation of the mediator pattern is relatively simple and can be achieved through the combination of interfaces and structures. In actual development, the mediator pattern is suitable for scenarios where there are complex interactions between objects, such as chat systems, UI component interactions, and event systems.