Em sistemas complexos, onde múltiplos objetos precisam interagir entre si, a comunicação direta pode criar uma teia de dependências de difícil manutenção. O Padrão Mediador soluciona isso introduzindo um objeto central que encapsula a lógica de interação entre os componentes. Essa abordagem transforma um relacionamento muitos-para-muitos caótico em uma estrutura organizada de um-para-muitos, promovendo baixo acoplamento entre as partes envolvidas.
A definição formal do padrão descreve como ele encapsula um conjunto de objetos com interações variáveis. A mediação garante que os objetos não se comuniquem diretamente, referenciando apenas ao mediador. Quando as regras de interação mudam, apenas o mediador necessita de ajustes, permitindo que as partes individuais sejam modificadas ou reutilizadas de forma independente.
O cenário ideal para aplicar este padrão surge quando múltiplos objetos apresentam comunicação complexa e interdependente. Alterar o comportamento de uma classe frequentemente exige mudanças cascata em diversas outras. O mediador centraliza esse controle, simplificando a manutenção e aumentando a flexibilidade do sistema.
Um exemplo prático é um sistema de controle residencial inteligente. Diferentes dispositivos — como termosatto, iluminação, fechaduras e alarmes — precisam coordenar suas ações (ex: ligar o ar-condicionado quando a temperatura sobe, ou desligar as luzes ao ativar o modo noturno). Um controlador central atua como mediador, processando eventos de um dispositivo e orquestrando as respostas dos demais.
Estrutura e Implementação
Primeiro, definimos uma interface abstrata para o mediador, que declara métodos para comunicação genérica.
// Interface do Mediador
public interface IMediadorResidencial {
void notificar(DispositivoBase remetente, string evento);
}
Em seguida, criamos a classe conncreta do mediador, que contém referências para todos os dispositivos e a lógica de roteamento das ações.
// Mediador Concreto: Central de Controle
public class ControladorCentral : IMediadorResidencial {
private Termostato _termometro;
private Iluminacao _iluminacao;
private SistemaAlarme _alarme;
public void RegistrarTermostato(Termostato t) => _termometro = t;
public void RegistrarIluminacao(Iluminacao i) => _iluminacao = i;
public void RegistrarAlarme(SistemaAlarme a) => _alarme = a;
public void notificar(DispositivoBase remetente, string evento) {
if (remetente == _termometro && evento == "temperaturaAlta") {
_iluminacao.AtivarModoNoite();
}
else if (remetente == _alarme && evento == "ativado") {
_iluminacao.DesligarTodas();
}
// ... outras regras de interação
}
}
A classe base dos colegas (dispositivos) mantém uma referência ao mediador.
// Classe Base para os Colaboradores
public abstract class DispositivoBase {
protected IMediadorResidencial _mediador;
public DispositivoBase(IMediadorResidencial mediador) {
_mediador = mediador;
}
public void Enviar(string evento) {
_mediador.notificar(this, evento);
}
public abstract void ReceberOrdem(string ordem);
}
As classes concretas dos dispositivos herdam da base e implementam suas lógicas específicas.
// Dispositivo Concreto: Termostato
public class Termostato : DispositivoBase {
public Termostato(IMediadorResidencial m) : base(m) { }
public void MonitorarTemperatura(int temp) {
if (temp > 25) {
Console.WriteLine("Termostato: Temperatura alta detectada.");
Enviar("temperaturaAlta");
}
}
public override void ReceberOrdem(string ordem) {
// Lógica específica do termostato ao receber uma ordem
}
}
// Dispositivo Concreto: Iluminação
public class Iluminacao : DispositivoBase {
public Iluminacao(IMediadorResidencial m) : base(m) { }
public void AtivarModoNoite() {
Console.WriteLine("Iluminação: Modo noturno ativado.");
}
public void DesligarTodas() {
Console.WriteLine("Iluminação: Todas as luzes desligadas.");
}
public override void ReceberOrdem(string ordem) { /* ... */ }
}
No teste de integração, conectamos os dispositivos através do mediador e disparamos uma ação para observar o efeito em cascata controlado.
// Teste de integração
public class TesteSistemaResidencial {
public static void Executar() {
var central = new ControladorCentral();
var temp = new Termostato(central);
var luzes = new Iluminacao(central);
var alarme = new SistemaAlarme(central);
central.RegistrarTermostato(temp);
central.RegistrarIluminacao(luzes);
central.RegistrarAlarme(alarme);
// Simula uma alteração de estado
temp.MonitorarTemperatura(28); // Deve ativar o modo noturno das luzes
}
}
Nesta estrutura, os dispositivos não interagem diretamente. O Termostato apenas notifica o mediador sobre um evento. O ControladorCentral contém a inteligência para decidir que a Iluminacao deve ser acionada. Se a regra mudar, por exemplo, para também abrir uma janela, apenas a classe do mediador é alterada.