Golang - Mediator Pattern

Golang - Mediator Pattern

The Mediator Pattern is a behavioral design pattern that helps to reduce the complexity of communication between objects by centralizing it through a mediator object. This pattern is part of the "Gang of Four" design patterns and it can be useful in scenarios where the communication between objects is becoming too complex and unmanageable.

In this article, we will explore how to implement the Mediator Pattern in Golang and provide a realistic code example.

Example Scenario

Let's imagine a scenario where we have a chat room application where multiple users can join and send messages to each other. In this case, we can have a mediator object that will handle the communication between the users.

Implementing the Mediator Pattern in Golang

To implement the Mediator Pattern in Golang, we will start by defining an interface for our mediator object. This interface will define the methods that our mediator object will use to communicate with the different objects in our system.

type mediator interface {
    addUser(user user)
    sendMessage(sender user, message string)
}

In the code above, we define our mediator interface with two methods: addUser and sendMessage. The addUser method will be used to add new users to our system, while the sendMessage method will be used to send messages between users.

Next, we will define our user struct which will represent a user in our system.

type user struct {
    id   int
    name string
}

In the code above, we define our user struct with an id and name fields.

Now, we can create our chatRoomMediator struct which will implement our mediator interface.

type chatRoomMediator struct {
    users []user
}

func (c *chatRoomMediator) addUser(user user) {
    c.users = append(c.users, user)
}

func (c *chatRoomMediator) sendMessage(sender user, message string) {
    for _, u := range c.users {
        if u.id != sender.id {
            fmt.Printf("%s sent message to %s: %s\\\\n", sender.name, u.name, message)
        }
    }
}

In the code above, we define our chatRoomMediator struct with a users field which is an array of user structs. We also implement the addUser and sendMessage methods from our mediator interface.

The addUser method appends a new user to our users array, while the sendMessage method loops through all our users and sends the message to all users except the sender.

Finally, we can create our main function and test our Mediator Pattern implementation.

func main() {
    mediator := &chatRoomMediator{}

    user1 := user{id: 1, name: "user1"}
    user2 := user{id: 2, name: "user2"}
    user3 := user{id: 3, name: "user3"}

    mediator.addUser(user1)
    mediator.addUser(user2)
    mediator.addUser(user3)

    mediator.sendMessage(user1, "Hello, everyone!")
}

In the code above, we create our mediator object and three user objects. We add these users to our mediator object using the addUser method, and then we send a message from user1 to everyone using the sendMessage method.

When we run our code, we should see the following output:

user1 sent message to user2: Hello, everyone!
user1 sent message to user3: Hello, everyone!

Comparison to Facade Pattern

The Facade Pattern is another design pattern that can be used to simplify the complexity of a system by providing a simplified interface to a larger body of code. While the Mediator Pattern focuses on simplifying communication between objects, the Facade Pattern focuses on simplifying the interface to a larger body of code.

In our chat room scenario, we could use the Facade Pattern to simplify the interface to the chat room system. For example, we could define a chatRoom struct which would have methods like joinRoom and sendMessage. These methods would call the appropriate methods on our chatRoomMediator object to handle the underlying complexity of the system.

The Mediator Pattern, on the other hand, focuses on simplifying communication between objects in a system. In our chat room scenario, the Mediator Pattern allows us to centralize communication between our users through a mediator object, which simplifies the communication between our users and reduces the overall complexity of the system.

Conclusion

In this article, we explored how to implement the Mediator Pattern in Golang. We created a realistic code example where we used the Mediator Pattern to manage the communication between users in a chat room application.

By using the Mediator Pattern, we were able to reduce the complexity of communication between our objects and centralize it through a mediator object.

We also compared the Mediator Pattern to the Facade Pattern and discussed how each pattern can be used to simplify the complexity of a system in different ways.


References

Did you find this article valuable?

Support Matthias Bruns by becoming a sponsor. Any amount is appreciated!