01Em uma frase
O Observer permite que um objeto anuncie que algo mudou e que qualquer número de outros objetos reaja, sem que o emissor saiba quem são, quantos são ou o que fazem.
Subject ou Observable; o receptor, de Observer ou Listener.02O problema que resolve
Quando a mudança de estado de um objeto precisa disparar reações em vários outros, aparecem duas saídas ingênuas, e as duas envelhecem mal:
- Chamada direta. O objeto que muda chama cada interessado pelo nome. Cada novo interessado obriga a editar a classe original, que acumula dependências de módulos sem relação com ela.
- Polling. Cada interessado verifica periodicamente se houve mudança. Gasta recurso quando nada acontece e atrasa a reação quando acontece.
O Observer inverte a direção do conhecimento: o interessado se registra, e o emissor passa a conhecer apenas uma interface.
03Participantes
| Papel | Responsabilidade | Operações |
|---|---|---|
| Subject | Mantém a lista de observadores e oferece o registro. | inscrever() cancelar() notificar() |
| Observer | Interface de retorno que todo interessado implementa. | atualizar() |
| ConcreteSubject | Guarda o estado real e chama notificar() quando ele muda. | getEstado() setEstado() |
| ConcreteObserver | Implementa a reação concreta ao aviso. | atualizar() |
04Como funciona
- Os observadores se registram no Subject com
inscrever(). - Algo altera o estado do Subject:
setEstado(). - O Subject chama
notificar(), que percorre a lista. - Para cada observador registrado, chama
atualizar(). - Cada observador reage, lendo o estado do Subject (pull) ou usando o dado recebido (push).
- Quem não quer mais ser avisado chama
cancelar(). É o passo mais esquecido e a origem do vazamento de memória.
Push, pull e híbrido
| Modelo | Assinatura | Vantagem | Custo |
|---|---|---|---|
| Push | atualizar(status, valor) | Direto; o observador não consulta nada. | O Subject presume o que cada um precisa; a assinatura cresce. |
| Pull | atualizar(subject) | Cada um busca só o que interessa; o Subject fica genérico. | Uma chamada extra; o observador conhece a API do Subject. |
| Híbrido | atualizar(evento) | Objeto de evento com o essencial e a referência. É o mais usado. | Mais uma classe para manter. |
05Implementação de referência
O teste do padrão: para acrescentar a emissão de nota fiscal, cria-se uma classe nova e chama-se inscrever. A classe Pedido não muda. É o Princípio Aberto/Fechado aplicado.
06Onde o padrão aparece
| Tecnologia | Como aparece |
|---|---|
| DOM / JavaScript | element.addEventListener('click', fn): o elemento é o Subject, a função é o Observer. |
| React / Vue | Estado reativo: o componente observa o estado e renderiza de novo quando ele muda. |
| Redux / Vuex / Pinia | store.subscribe(listener): a interface observa a store. |
| Java SE | ActionListener, PropertyChangeListener, Flow.Subscriber. As antigas Observable/Observer foram depreciadas no Java 9. |
| Spring | ApplicationEventPublisher e @EventListener. |
| Django | Signals: post_save, pre_delete e receptores conectados. |
| RxJS | Observable.subscribe(): Observer estendido com fluxo, operadores e cancelamento. |
| Webhooks | Observer sobre HTTP: você registra uma URL e o serviço a chama quando o evento ocorre. |
| Kafka / RabbitMQ / SNS | Pub/Sub distribuído: mesma intenção, com intermediário e entrega assíncrona. |
| MVC | A View observa o Model. É o uso original do padrão, no Smalltalk-80. |
07Vantagens
- Baixo acoplamento: o Subject depende só da interface
Observer. - Aberto/Fechado: novos observadores sem alterar o Subject.
- Vínculo dinâmico: inscrição e cancelamento em execução.
- Broadcast: um evento, N reações, sem o emissor saber quantas.
- Responsabilidade única: cada reação isolada e testável sozinha.
- Reuso independente de Subject e de Observer.
08Desvantagens
- Vazamento de memória: o lapsed listener nunca é coletado.
- Ordem indefinida de notificação.
- Cascatas e ciclos quando um observador altera outro Subject.
- Depuração difícil: o fluxo deixa de ser explícito na pilha.
- Bloqueio e falha em cadeia na versão síncrona.
- Modificação concorrente da lista durante a notificação.
09Observer × Publish/Subscribe
| Critério | Observer (GoF) | Pub/Sub (mensageria) |
|---|---|---|
| Conhecimento | O Subject mantém a lista de observadores. | Publicador e assinante não se conhecem; há um broker. |
| Acoplamento | Baixo, com referência direta em memória. | Quase nulo, só o nome do tópico ou canal. |
| Escopo | Dentro de um processo. | Entre processos, serviços e máquinas. |
| Execução | Geralmente síncrona. | Assíncrona, com fila, retentativa e persistência. |
| Exemplos | addEventListener, Swing, Spring Events. | Kafka, RabbitMQ, SNS, webhooks. |
10Quando usar e quando evitar
Use quando
- Uma mudança em um objeto exige mudanças em outros que não são conhecidos de antemão.
- O conjunto de interessados varia em tempo de execução.
- Você quer separar o que aconteceu de o que fazer a respeito.
- O mesmo evento alimenta interface, log, métricas e integrações ao mesmo tempo.
Evite quando
- Existe um único dependente fixo: a chamada direta é mais legível.
- A ordem das reações é requisito de negócio.
- É preciso garantia de entrega ou reprocessamento: use fila.
- As reações devem ser transacionais junto com a mudança de estado.
11Padrões relacionados
- Mediator: também desacopla, mas centraliza a comunicação num intermediário. O Observer distribui o aviso a quem se inscreveu.
- MVC: usa Observer na relação Model → View.
- Command: empacota a reação a ser executada na notificação.
- Chain of Responsibility: entrega o aviso a um receptor por vez, até alguém tratar. O Observer entrega a todos.
- Singleton: combinado para expor um barramento de eventos global. Use com cautela, porque dificulta os testes.
12Checklist de implementação
- Separe o que muda (estado) de quem reage (comportamentos independentes).
- Declare a interface
Observercom um único método de atualização. - No Subject, mantenha a coleção de observadores e os métodos de registro.
- Chame
notificar()depois de o estado estar consistente. - Percorra uma cópia da lista, para suportar cancelamento durante a notificação.
- Trate a exceção de cada observador isoladamente, para que um não derrube os outros.
- Garanta o
cancelar()no ciclo de vida do observador, ou use referências fracas. - Se precisar de ordem, assincronia ou entrega garantida, passe para fila ou mensageria.
13Perguntas prováveis da banca
Mesma intenção, escalas diferentes. No Observer o Subject conhece a lista e a chamada costuma ser síncrona, dentro do processo. No Pub/Sub há um broker no meio, e publicador e assinante não se conhecem.
Não eram serializáveis, não garantiam ordem nem suportavam concorrência, e Observable era uma classe, o que obrigava herança e gastava a única superclasse disponível. Desde o Java 9 recomenda-se PropertyChangeListener ou a API java.util.concurrent.Flow.
Principalmente o Aberto/Fechado: estende-se o comportamento acrescentando observadores, sem modificar o Subject. Também a Responsabilidade Única e a Inversão de Dependência, já que o Subject depende de uma abstração.
Garantindo o cancelar() no fim do ciclo de vida do observador (em um finally, dispose ou onDestroy), ou guardando os observadores por referência fraca (WeakReference).
Na implementação ingênua ele interrompe o laço e os seguintes não são notificados. A correção é capturar a exceção de cada observador dentro do notificar(), registrar o erro e continuar.
O padrão não define. A implementação clássica do GoF é síncrona: notificar() só retorna quando todos reagiram. Versões assíncronas despacham para uma fila ou um pool de threads.
14Referências
- GAMMA, E.; HELM, R.; JOHNSON, R.; VLISSIDES, J. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1994. Cap. 5, “Observer”.
- FREEMAN, E.; ROBSON, E. Head First Design Patterns. 2. ed. O’Reilly, 2020. Cap. 2.
- VALENTE, M. T. Engenharia de Software Moderna. Cap. 6, Padrões de Projeto.
- Refactoring Guru. Observer. refactoring.guru/pt-br/design-patterns/observer
- Oracle. Java Platform SE API: java.util.concurrent.Flow.