Implementação Básica
Introdução à Implementação Prática
Após compreendermos os fundamentos teóricos do padrão Mediator, é essencial consolidar esse conhecimento através da implementação concreta. Nesta seção, analisaremos uma implementação básica em C#/.NET que demonstra como o padrão Mediator pode ser aplicado para desacoplar componentes de interface do usuário em um diálogo simples. Este exemplo servirá como base para entendermos a estrutura, os componentes e o fluxo de comunicação característico do padrão.
Cenário de Exemplo: Diálogo de Confirmação
Vamos considerar um cenário prático comum em aplicações: um diálogo de confirmação que requer interação do usuário. Este diálogo contém três componentes básicos:
TextBox: Um campo de texto onde o usuário deve digitar seu nome para confirmação.Checkbox: Uma caixa de seleção que o usuário deve marcar para aceitar os termos.Button: Um botão de confirmação que só deve estar habilitado quando ambas as condições forem satisfeitas:O campo de texto não está vazio
A caixa de seleção está marcada
A lógica de negócio é clara: o botão só pode ser usado quando o usuário forneceu seu nome e aceitou os termos. Sem o Mediator, implementar essa lógica criaria dependências diretas entre os três componentes.
Estrutura do Projeto e Configuração Inicial
Para iniciar nossa implementação, criamos um projeto de console básico:
dotnet new console -o MyMediatorApp01Este comando cria uma nova aplicação de console que servirá como ambiente para nosso exemplo. A simplicidade de uma aplicação de console permite focar na essência do padrão sem a complexidade adicional de frameworks de UI.
No arquivo Program.cs, começamos configurando o cenário inicial:
Esta configuração inicial estabelece a estrutura fundamental do padrão Mediator:
Instanciação dos Componentes: Criamos três componentes concretos que representam elementos de UI.
Criação do Mediador: Instanciamos o
DialogMediator, que será o coordenador central.Associação Bidirecional: Conectamos cada componente ao mediador através do método
SetMediator(). Esta é uma etapa crucial - o mediador conhece os componentes (através das propriedades) e os componentes conhecem o mediador (através da referência_mediator).
Definição da Interface do Mediador
O coração do padrão Mediator reside na interface que define como os componentes se comunicam com o mediador:
Esta interface minimalista define um único método:
Notify: O método pelo qual todos os componentes comunicam eventos ao mediador.sender: O componente que originou o evento, permitindo ao mediador identificar quem está notificando.@event: Uma string que descreve qual evento ocorreu. O uso de@event(com@) é necessário porqueeventé uma palavra reservada em C#.
A simplicidade desta interface é intencional - ela estabelece um contrato universal para comunicação, independente dos componentes específicos envolvidos.
Componente Base Abstrato
Para evitar repetição de código e garantir consistência, definimos uma classe base abstrata para todos os componentes:
Esta classe base fornece:
Referência ao Mediador: Cada componente mantém uma referência protegida ao mediador.
Método de Configuração: O método
SetMediatorpermite injetar o mediador após a criação do componente.
A abordagem com classe base é comum, mas não obrigatória. Alternativamente, poderíamos usar uma interface IComponent com o método SetMediator, ou até mesmo injetar o mediador no construtor de cada componente.
Implementação dos Componentes Concretos
TextBox: Componente de Entrada de Texto
Características:
Estado Interno: Mantém o texto digitado na propriedade
Text.Método de Ação:
Inputsimula a digitação do usuário.Notificação ao Mediador: Após cada alteração, notifica o mediador com o evento
"TextChanged".Baixo Acoplamento: O
TextBoxnão tem conhecimento sobre oCheckboxouButton- apenas notifica o mediador.
Checkbox: Componente de Seleção
Características:
Estado Booleano: Representa se a caixa está marcada ou não.
Ação de Alternância:
Toggleinverte o estado atual.Notificação: Comunica ao mediador quando o estado muda (
"CheckedChanged").
Button: Componente de Ação
Características:
Estado de Habilitação: Controla se o botão pode ser clicado.
Comportamento Condicional: A ação
Clickverifica se está habilitado antes de processar.Notificação Pós-Ação: Mesmo quando desabilitado, o botão notifica o mediador sobre a tentativa de clique.
Implementação do Mediador Concreto
O DialogMediator é onde reside toda a lógica de coordenação:
Análise Detalhada:
Propriedades Específicas: Diferente da interface genérica
IMediator, o mediador concreto conhece os tipos específicos dos componentes. Este é um trade-off comum - quanto mais genérico o mediador, mais reutilizável, mas também mais complexo.Filtro de Eventos: O mediador verifica se o evento recebido é relevante para sua lógica de coordenação. Neste caso, só reage a
"TextChanged"e"CheckedChanged", ignorando"ButtonClicked".Lógica de Coordenação Centralizada: A regra de negócio - "habilitar botão apenas quando texto não vazio E checkbox marcado" - está concentrada em um único local.
Ação sobre Componentes: O mediador modifica diretamente o estado dos componentes (definindo
Button.IsEnabled).Transparência: As mensagens de log (
[Mediator]...) tornam visível o processo de decisão, facilitando o entendimento durante a execução.
Simulação de Interação do Usuário
O código principal simula uma sequência de interações do usuário:
Fluxo de Execução Analisado:
Clique Inicial (
button.Click()):Botão está desabilitado por padrão
Mensagem:
"[Button] O botão está desabilitado"Mediador é notificado, mas ignora o evento
Entrada de Texto (
textBox.Input("João")):TextBox atualiza seu estado interno
Notifica mediador com
"TextChanged"Mediador avalia: texto existe (
true) mas checkbox não marcado (false)Botão permanece desabilitado
Saída:
"[TextBox] João"→"[Mediator] Botão desabilitado"
Marcação do Checkbox (
checkbox.Toggle()):Checkbox alterna para
trueNotifica mediador com
"CheckedChanged"Mediador avalia: texto existe (
true) E checkbox marcado (true)Habilita o botão
Saída:
"[Checkbox] Marcado: True"→"[Mediator] Botão habilitado"
Clique Válido (
button.Click()):Botão agora está habilitado
Processa o clique
Saída:
"[Button] Clique processado"
Desmarcação do Checkbox (
checkbox.Toggle()):Retorna à condição inválida
Desabilita o botão novamente
Tentativa de Clique Inválido (
button.Click()):Confirma que o botão está desabilitado
Execução e Saída do Programa
Ao executar dotnet run, observamos a seguinte sequência de saída:
Análise da Saída:
Rastreabilidade Clara: Cada ação é claramente identificada pelo componente de origem (
[TextBox],[Checkbox],[Button],[Mediator]).Visibilidade da Decisão: As mensagens do mediador (
[Mediator] Botão habilitado/desabilitado) tornam explícita a lógica de decisão em tempo real.Fluxo Síncrono: A notificação e resposta são imediatas - quando um componente muda, o mediador reage instantaneamente.
Consistência de Estado: O estado do sistema (botão habilitado/desabilitado) sempre reflete corretamente as condições de negócio.
Pontos de Atenção e Considerações
Vantagens Evidenciadas nesta Implementação
Desacoplamento Efetivo: Nenhum componente referencia outro diretamente.
Centralização da Lógica: A regra de habilitação está em um único local.
Facilidade de Modificação: Para alterar a lógica (ex.: exigir texto com mínimo de 3 caracteres), modifica-se apenas o mediador.
Testabilidade: Cada componente pode ser testado isoladamente, com um mediador mock.
Limitações e Melhorias Potenciais
Tipagem Forte no Mediador: O
DialogMediatorconhece tipos concretos, limitando reutilização. Poderíamos usar interfaces (ITextBox,ICheckbox,IButton).Strings para Eventos: O uso de strings para eventos é propenso a erros (erros de digitação). Enums ou constantes seriam mais seguros:
Configuração Manual: A associação entre componentes e mediador é manual. Em aplicações reais, um contêiner de DI (Injeção de Dependência) poderia gerenciar isso.
Mediador como "God Object": Em sistemas maiores, um único mediador pode tornar-se muito complexo. A solução é criar múltiplos mediadores especializados.
Ausência de Suporte a Eventos Assíncronos: Em aplicações com UI real, muitas interações são assíncronas.
Conclusão da Implementação Básica
Esta implementação básica do padrão Mediator em C# demonstra os conceitos fundamentais de forma prática e acessível. Através de um exemplo concreto de diálogo de confirmação, vimos:
Como estruturar os componentes, a interface do mediador e o mediador concreto.
Como estabelecer o canal de comunicação bidirecional entre componentes e mediador.
Como centralizar a lógica de coordenação em um único ponto.
Como os componentes permanecem desacoplados, conhecendo apenas o mediador.
Como o fluxo de notificação e resposta mantém o sistema consistente.
Esta implementação serve como base sólida para compreender padrões mais avançados e bibliotecas como o MediatR, que aplicam os princípios do Mediator em cenários de aplicação mais complexos, como CQRS e mensagens entre camadas da aplicação.
O verdadeiro poder do padrão Mediator revela-se quando aplicado a sistemas com dezenas ou centenas de componentes inter-relacionados, onde a abordagem tradicional de comunicação direta tornaria o código praticamente impossível de manter e evoluir.
Atualizado