Design de software

Padrão Mediator em Swift: guia completo (delegue a comunicação entre objetos)

Se você já fez um app iOS crescer um pouco, provavelmente já encontrou este momento.

4 min de leitura
Imagem de capa de Padrão Mediator em Swift: guia completo (delegue a comunicação entre objetos)

Se você já fez um app iOS crescer um pouco, provavelmente já encontrou este momento.

Uma tela tem cinco ou seis views: quando A muda, B também precisa mudar; quando B muda, C precisa ser ajustada.

Logo, as views passam a referenciar umas às outras diretamente e ficam enroladas como um novelo.

É exatamente isso que o padrão Mediator ajuda a organizar.

O padrão Mediator em Swift reduz o acoplamento fazendo os objetos se comunicarem apenas com um Mediator, sem referências diretas entre si.

Neste artigo, explico o que é o padrão Mediator, quando usá-lo e como implementá-lo em Swift com código de exemplo.


O que é o padrão Mediator?

Em uma frase:

Coloque um Mediator entre os objetos que precisam se comunicar e faça toda a conversa passar por ele.

Pense em uma torre de controle de aeroporto.

Se os aviões falassem pelo rádio “pouse primeiro” e “eu vou primeiro”, aconteceria um grande acidente.

Por isso, cada avião conversa apenas com a torre, que organiza a ordem.

Aqui, os aviões são os objetos do nosso código, e a torre é o Mediator.

O padrão Mediator resolve principalmente isto:

  • Remover referências diretas: o objeto A não precisa conhecer B, C e D individualmente
  • Concentrar a lógica de comunicação: regras complexas de interação ficam reunidas em um Mediator
  • Aumentar a reutilização: objetos independentes são fáceis de reutilizar em outras telas

Quando usar o padrão Mediator?

Ele não é ideal para todas as situações. Considero adotá-lo quando vejo sinais como estes.

Quando os objetos conhecem demais uns aos outros, ou seja, ao abrir uma classe surgem referências em cadeia para vários outros objetos.

Outro sinal é precisar alterar vários objetos relacionados ao mesmo tempo para mudar uma única parte da lógica.

Os usos mais comuns são:

Situação Exemplo
UI de tela complexa Vários botões e labels reagem em cadeia aos valores do formulário
Coordenação de componentes Encaminhamento de mensagens entre participantes de uma sala de chat
Controle de workflow Gerenciamento do estado das views em cada etapa do pagamento

Por outro lado, se houver apenas dois ou três objetos e a relação for simples, é melhor não usar.

O Mediator pode crescer sem necessidade e virar um “God Object”.


Como implementar o padrão Mediator em Swift?

Vamos usar uma sala de chat como exemplo. Os participantes trocam mensagens pela sala (o Mediator), em vez de enviarem mensagens diretamente uns aos outros.

Primeiro, definimos o protocolo que o Mediator deve seguir e os participantes.

// Regras que o Mediator deve seguir
protocol ChatMediator {
    func send(_ message: String, from user: User)
    func add(_ user: User)
}

O ponto principal é que cada participante conhece apenas o Mediator e não referencia diretamente os outros participantes.

class User {
    let name: String
    weak var mediator: ChatMediator?  // Evitar referências cíclicas

    init(name: String) { self.name = name }

    func send(_ text: String) {
        mediator?.send(text, from: self)  // Delegar ao Mediator
    }
    func receive(_ text: String) {
        print("\(name) Recebido: \(text)")
    }
}

Por fim, o Mediator cuida das regras reais de entrega: transmite a mensagem apenas para quem não a enviou.

class ChatRoom: ChatMediator {
    private var users: [User] = []
    func add(_ user: User) { users.append(user); user.mediator = self }
    func send(_ message: String, from user: User) {
        users.filter { $0 !== user }
             .forEach { $0.receive("[\(user.name)] \(message)") }
    }
}

Mesmo que o número de usuários cresça, não é preciso alterar a classe User. Só a ChatRoom conhece as regras de entrega.

Todos conhecem apenas a ChatRoom; ninguém conhece os outros
Todos conhecem apenas a ChatRoom; ninguém conhece os outros
Execute o código de exemplo e digite junto para entender na prática
Execute o código de exemplo e digite junto para entender na prática

Mediator vs. Observer: qual é a diferença?

Muita gente confunde esses dois padrões.

Resumindo, a diferença é esta.

Categoria Mediator Observer
Direção Comunicação muitos-para-muitos centralizada Notificação um-para-muitos (publicação-assinatura)
Relação Os objetos interagem por meio do Mediator O observado notifica os observadores
Foco Coordenação mútua complexa Propagação de mudanças de estado

Em termos simples, o Observer anuncia unilateralmente: “Eu mudei!”

O Mediator decide “quem deve fazer o quê nesta situação?” e coordena os objetos.

No Swift, Combine e NotificationCenter se aproximam da família Observer, enquanto o Mediator geralmente é implementado diretamente.


Perguntas frequentes (Q&A)

P. E se o Mediator ficar grande demais?

Como a lógica se concentra ali, o Mediator pode ficar inchado. Divida-o em vários Mediators por funcionalidade ou extraia a lógica interna para helpers separados.

P. Preciso usar weak obrigatoriamente?

Sim. Se participantes e Mediator referenciarem um ao outro fortemente, referências cíclicas causarão vazamento de memória. Deixe um dos lados como weak, como no exemplo.

P. Posso usar com SwiftUI?

Sim. Muitas vezes, o ViewModel atua na prática como Mediator entre as views. É natural coordenar o estado de várias views por meio de um único ViewModel.

Desenhei um Mediator, organizei as relações e minha cabeça ficou muito mais leve
Desenhei um Mediator, organizei as relações e minha cabeça ficou muito mais leve

Se seus objetos estão tão interligados que dá medo de mexer no código, experimente adicionar o padrão Mediator.

Basta criar um Mediator para deixar cada objeto muito mais leve e facilitar futuras adições de funcionalidades.

Recomendo aplicar o código de exemplo de hoje em um projeto pequeno. Ao escrever você mesmo, tudo fica claro. 😊

Continue lendo