AULA 17
MÓDULO 5
design patterns
⏱ 60 min
Padrão Observer e Decorator
Observer: notificação desacoplada via interface. Decorator: responsabilidades dinâmicas sem herança. Observer vs Pub/Sub: quando usar cada um.
ObserverDecoratorinterfacecomposiçãoin-processPub/SubList
Padrão Observer — notificação desacoplada
Quando um pedido é confirmado, o sistema precisa: decrementar estoque, enviar email, registrar no analytics. Quem deve ter esse conhecimento? Se for a classe Pedido, ela precisaria importar EmailService, EstoqueService, AnalyticsService — acoplamento máximo.
o problema sem Observer
Pedido.confirmar() com 50 linhas chamando serviços diferentes. Adicionar notificação no WhatsApp = modificar Pedido. Pedido se torna um deus que conhece tudo.«interface» Observador
+ atualizar(Evento e): void
↑ implements
ObsEstoque ObsEmail ObsAnalytics
Pedido (sujeito observável)
- observadores: List<Observador>
+ adicionar(Observador o): void
+ notificarTodos(Evento e): void
Padrão Decorator — responsabilidades dinâmicas
Decorator adiciona responsabilidades a um objeto em runtime sem herança. Em vez de criar subclasses para cada combinação, você empilha decoradores como camadas.
o exemplo clássico
Café R$2,00. + Leite: R$2,50. + Açúcar: R$2,70. + Canela: R$3,20. Com herança: CaféComLeite, CaféComLeiteMaisAçúcar, etc — explosão combinatória. Com Decorator: new Canela(new Açúcar(new Leite(new CaféSimples()))).Observer vs Pub/Sub — diferença
Observer e Pub/Sub resolvem o mesmo problema de formas diferentes.
| Aspecto | Observer | Pub/Sub |
|---|---|---|
| Acoplamento | Indireto (via interface) | Total — via broker |
| Escopo | In-process (mesmo processo) | Cross-process (sistemas distribuídos) |
| Tecnologias | Java nativo, EventEmitter | Kafka, RabbitMQ, Redis Pub/Sub |
| Persistência | Não | Sim (mensagens em fila) |
java
// Padrão Observer public interface Observador { void atualizar(String evento, Object dados); } public class ObservadorEstoque implements Observador { public void atualizar(String evento, Object dados) { if ("PEDIDO_CONFIRMADO".equals(evento)) System.out.println("[Estoque] decrementando: " + dados); } } public class ObservadorEmail implements Observador { public void atualizar(String evento, Object dados) { if ("PEDIDO_CONFIRMADO".equals(evento)) System.out.println("[Email] enviando confirmação para: " + dados); } } // Sujeito observável public class Pedido { private final List<Observador> observadores = new ArrayList<>(); public void adicionarObservador(Observador o) { observadores.add(o); } public void removerObservador(Observador o) { observadores.remove(o); } private void notificarTodos(String evento, Object dados) { observadores.forEach(o -> o.atualizar(evento, dados)); } public void confirmar() { // Pedido SÓ faz o que é dele — não sabe quem observa notificarTodos("PEDIDO_CONFIRMADO", this); } } // Padrão Decorator — Café public interface Cafe { double getPreco(); String getDescricao(); } public class CafeSimples implements Cafe { public double getPreco() { return 2.0; } public String getDescricao() { return "Café"; } } public abstract class DecoradorCafe implements Cafe { protected Cafe base; DecoradorCafe(Cafe c) { this.base = c; } } public class Leite extends DecoradorCafe { Leite(Cafe c) { super(c); } public double getPreco() { return base.getPreco() + 0.50; } public String getDescricao() { return base.getDescricao() + ", Leite"; } } // Uso — empilhar decoradores Cafe pedido = new Leite(new CafeSimples()); // pedido.getPreco() → 2.50, getDescricao() → "Café, Leite"
quiz · aula 17
Teste seus conhecimentos em Java
0/3 respondidas
QUESTÃO 01
No padrão Observer, o sujeito (Pedido) precisa conhecer as classes concretas dos observadores?
QUESTÃO 02
Por que Decorator usa composição em vez de herança para adicionar comportamento?
QUESTÃO 03
Qual diferença principal entre Observer e Pub/Sub?
0/3