Mediator
Intenção (GoF)
Seção intitulada “Intenção (GoF)”Definir um objeto que encapsula como um conjunto de objetos interage. O Mediator promove o baixo acoplamento ao evitar que os objetos se refiram uns aos outros explicitamente, permitindo variar suas interações independentemente.
Problema
Seção intitulada “Problema”Quando muitos objetos precisam colaborar, referências diretas entre todos criam uma malha N-para-N: cada objeto conhece vários outros, a lógica de interação fica espalhada e qualquer mudança se propaga por toda a teia. O caso clássico é uma tela com muitos widgets cujo comportamento depende do estado uns dos outros (habilitar/desabilitar, validar, sincronizar).
Estrutura
Seção intitulada “Estrutura”- Mediator: interface que declara os métodos de comunicação usados pelos colegas (ex.:
notify(sender, event)). - ConcreteMediator: conhece e coordena os colegas, concentrando a lógica de interação.
- Colleague: cada componente conhece apenas o mediador, não os outros colegas; ao mudar de estado, avisa o mediador.
Consequências e trade-offs
Seção intitulada “Consequências e trade-offs”Prós
- Reduz acoplamento entre colegas: de N-para-N para N-para-1.
- Centraliza e torna explícita a lógica de interação, facilitando alterá-la.
- Colegas ficam mais reutilizáveis e simples.
Contras
- Risco de o mediador virar God Object, absorvendo toda a complexidade que antes estava distribuída.
- Ponto central de mudança e de falha.
- Pode esconder o fluxo real de dados sob camadas de notificação.
Quando NÃO usar
Seção intitulada “Quando NÃO usar”Quando os objetos têm poucas interações simples e diretas, ou quando a coordenação natural pertence a um único agregado. Introduzir um mediador para duas ou três colaborações triviais só adiciona indireção.
Exemplo em Java
Seção intitulada “Exemplo em Java”Antes: colegas acoplados entre si
Seção intitulada “Antes: colegas acoplados entre si”public class LoginForm {
private final UsernameField username = new UsernameField(); private final PasswordField password = new PasswordField(); private final SubmitButton submit = new SubmitButton();
public void onUsernameChanged() { submit.setEnabled(!username.isEmpty() && !password.isEmpty()); }
public void onPasswordChanged() { submit.setEnabled(!username.isEmpty() && !password.isEmpty()); }}O form já centraliza as referências, mas a regra de habilitação está duplicada nos handlers e cresce a cada novo widget: adicionar um campo “lembrar-me” ou um captcha obriga a editar todos os on*Changed e a espalhar a condição. É essa teia de atualizações cruzadas — que em UIs reais degenera em widgets se referenciando diretamente (N-para-N) — que o mediador elimina.
Depois: mediador coordena os colegas
Seção intitulada “Depois: mediador coordena os colegas”public interface DialogMediator { void notify(Component sender, String event);}
public abstract class Component { protected DialogMediator mediator; public void setMediator(DialogMediator mediator) { this.mediator = mediator; }}
public class TextField extends Component { private String value = ""; public void setValue(String value) { this.value = value; mediator.notify(this, "changed"); } public boolean isEmpty() { return value.isBlank(); }}
public class Button extends Component { private boolean enabled; public void setEnabled(boolean enabled) { this.enabled = enabled; } public boolean isEnabled() { return enabled; }}Mediador concreto com a lógica de interação:
public class LoginDialog implements DialogMediator {
private final TextField username = new TextField(); private final TextField password = new TextField(); private final Button submit = new Button();
public LoginDialog() { username.setMediator(this); password.setMediator(this); submit.setMediator(this); }
public void notify(Component sender, String event) { if (event.equals("changed") && (sender == username || sender == password)) { submit.setEnabled(!username.isEmpty() && !password.isEmpty()); } }
public TextField username() { return username; } public TextField password() { return password; } public Button submit() { return submit; }}Os campos não se conhecem; toda a coordenação vive no LoginDialog.
Diagrama
Seção intitulada “Diagrama”classDiagram
class DialogMediator {
<<interface>>
+notify(sender, event) void
}
class LoginDialog {
-TextField username
-TextField password
-Button submit
+notify(sender, event) void
}
class Component {
#DialogMediator mediator
+setMediator(m) void
}
class TextField
class Button
DialogMediator <|.. LoginDialog
Component <|-- TextField
Component <|-- Button
Component o--> DialogMediator
LoginDialog o--> TextField
LoginDialog o--> Button
Mediator vs. Observer
Seção intitulada “Mediator vs. Observer”Ambos reduzem acoplamento na comunicação, mas de formas opostas:
- Observer: comunicação descentralizada e um-para-muitos. O subject não conhece os observers concretos; a relação é de broadcast de mudanças de estado. Não há um coordenador — cada observer reage por conta própria.
- Mediator: comunicação centralizada e N-para-1. Há um coordenador que conhece os colegas e implementa a lógica de interação entre eles. A intenção é orquestrar colaborações complexas, não apenas notificar.
Regra prática: use Observer quando um evento deve simplesmente propagar a muitos interessados independentes; use Mediator quando a lógica de “quem faz o quê em resposta a quê” é rica e precisa morar num lugar. Um mediador pode inclusive usar Observer internamente para receber os avisos dos colegas.
Anti-padrões e erros comuns
Seção intitulada “Anti-padrões e erros comuns”- Mediador God Object: concentrar regras de negócio e conhecimento de todos os colegas até se tornar uma classe monstruosa e frágil. Divida por contexto e mantenha o mediador focado em interação, não em regra de domínio.
- Colegas que continuam se referenciando por baixo do mediador, anulando o desacoplamento.
- Usar Mediator onde Observer bastaria (simples broadcast), pagando por centralização desnecessária.
- Lógica de domínio dentro do mediador de UI, misturando camadas.
Relações
Seção intitulada “Relações”- Padrão comportamental de Padrões Comportamentais / Design Patterns (GoF).
- Contrasta com Observer (descentralizado vs. centralizado) e frequentemente o usa por dentro.
- Ajuda o SRP - Single Responsibility Principle nos colegas, mas ameaça-o no próprio mediador se crescer demais.
- Relacionado a Facade (ambos simplificam interação), embora com intenções distintas.
- Índice: Design Patterns (GoF) · Catálogo de Patterns.
Perguntas de revisão
Seção intitulada “Perguntas de revisão”1. Que tipo de relação de comunicação o Mediator elimina e por qual ele a substitui?
Resposta
Elimina as relações diretas N-para-N entre colegas (cada objeto conhecendo vários outros) e as substitui por relações N-para-1: todos conversam apenas com o mediador, que concentra a lógica de interação.
2. Qual o principal risco de design ao adotar Mediator?
Resposta
O mediador virar um God Object: ao absorver o conhecimento de todos os colegas e a lógica de interação, pode inchar até se tornar uma classe central frágil, difícil de manter e testar. A mitigação é mantê-lo focado em coordenação e dividir por contexto.
3. Como distinguir Mediator de Observer?
Resposta
Observer é descentralizado e um-para-muitos: o subject faz broadcast sem conhecer os observers concretos. Mediator é centralizado e N-para-1: um coordenador conhece os colegas e implementa a lógica de quem reage a quê. Observer notifica; Mediator orquestra.
4. Em que caso introduzir um Mediator é overengineering?
Resposta
Quando há poucas interações simples e diretas entre objetos, ou quando a coordenação pertence naturalmente a um único agregado. Um mediador para duas ou três colaborações triviais só adiciona indireção e um ponto central desnecessário.