1. O que é o Padrão Mediator

O Padrão Mediator é um padrão de design comportamental que reduz as dependências diretas entre objetos transferindo a comunicação deles para um objeto mediador. No Padrão Mediator, os objetos não se comunicam mais diretamente entre si, mas sim por meio do objeto mediador.

2. Características e Vantagens do Padrão Mediator

As características e vantagens do Padrão Mediator são as seguintes:

  • Reduz o acoplamento direto entre objetos, reduzindo a complexidade do sistema.
  • Simplifica a comunicação entre objetos, tendo um objeto mediador que gerencia a comunicação.
  • Centraliza o controle das interações entre objetos, facilitando a extensão e manutenção.

3. Exemplos do Mundo Real do Padrão Mediator

O Padrão Mediator possui muitas aplicações em cenários da vida real. Por exemplo, em um sistema de agendamento de aeroportos, o despachante atua como o mediador, enquanto os diferentes módulos, como aviões e tráfego terrestre, atuam como classes colegas que se comunicam e coordenam por meio do despachante.

4. Implementação do Padrão Mediator em Golang

4.1 Introdução ao Diagrama de Classe UML

A seguir está o diagrama de classe UML para o Padrão Mediator em Golang:

Padrão Mediator em Golang

4.2 Introdução do Exemplo

Neste exemplo, implementaremos uma aplicação de sala de chat simples usando o Padrão Mediator para gerenciar a comunicação entre diferentes usuários.

4.3 Passo 1 da Implementação: Definir a Interface do Mediator e o Mediator Concreto

Primeiro, definimos uma interface de mediador e uma classe de mediador concreta:

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 Passo 2 da Implementação: Definir a Interface do Colega e Colegas Concretos

Em seguida, definimos uma interface de colega e classes de colegas concretos:

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 recebeu a mensagem: %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 recebeu a mensagem: %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 Passo 3 da Implementação: Gerenciamento de Colegas no Mediator

Na classe mediador específica, precisamos implementar o método registerColleague e o método sendMessage para gerenciar a comunicação entre as classes colegas:

func main() {
    mediator := &ConcreteMediator{
        colleagues: make(map[string]Colleague),
    }

    colleagueA := &ConcreteColleagueA{
        mediator: mediator,
        name:     "Colega A",
    }
    colleagueB := &ConcreteColleagueB{
        mediator: mediator,
        name:     "Colega B",
    }

    mediator.registerColleague(colleagueA)
    mediator.registerColleague(colleagueB)

    colleagueA.sendMessage("Olá, Mundo!")
    colleagueB.sendMessage("Oi, tudo bem?")
}

Na função main, criamos um objeto mediador específico e dois objetos colegas específicos, registramos os objetos colegas por meio do objeto mediador e realizamos testes de comunicação.