Observer
Definição (GoF): “Definir uma dependência um-para-muitos entre objetos, de modo que quando um objeto (Subject) muda de estado, todos os seus dependentes (Observers) são notificados e atualizados automaticamente.”
Problema
- Precisamos propagar mudanças de um objeto (fonte de dados) para várias visualizações.
- Abordagem ingênua: ou o Subject chama cada tela manualmente (alto acoplamento), ou as telas fazem polling periódico (ineficiente, duplicado).
classDiagram
direction LR
class WeatherStationBad {
-temp: double
+setTemp(t)
+getTemp(): double
}
class DisplayA { +refresh(WeatherStationBad) }
class DisplayB { +refresh(WeatherStationBad) }
%% Variante 1: Subject conhece os displays (alto acoplamento)
WeatherStationBad --> DisplayA : chama direto
WeatherStationBad --> DisplayB : chama direto
%% Variante 2: Polling (cada display busca sozinho)
DisplayA --> WeatherStationBad : polling
DisplayB --> WeatherStationBad : polling
Código Fonte (Problema — acoplado / polling)
- Como reduzir acoplamento, evitar polling, e permitir que N telas se atualizem automaticamente?
Solução (GoF)
- Introduzir Subject com operações
attach(),detach(),notifyObservers(). - Observers registram interesse e implementam
update(). - Quando o estado muda, o Subject notifica todos (estilo pull: os observers consultam o estado).
Diagrama GoF Genérico (Mermaid)
classDiagram
direction LR
class Subject {
+attach(o: Observer)
+detach(o: Observer)
#notifyObservers()
}
class Observer {
<<interface>>
+update()
}
class ConcreteSubject {
-state
+getState()
+setState(s)
}
class ConcreteObserver {
-subject: ConcreteSubject
+update()
}
Subject <|-- ConcreteSubject
Observer <|.. ConcreteObserver
ConcreteSubject o-- Observer : mantém lista
ConcreteObserver --> ConcreteSubject : consulta (pull)
Código Fonte (Genérico — estilo pull)
| ConcreteSubject.java | |
|---|---|
Exemplo — Estação Meteorológica (Temperatura/Umidade)
Diagrama da Solução
classDiagram
direction LR
class WeatherStation {
<<Subject>>
-temp: double
-humidity: double
+setMeasurements(t, h)
+getTemp(): double
+getHumidity(): double
}
class Display { <<Observer>> +update() }
class TempDisplay { +update() }
class StatsDisplay { +update() }
WeatherStation o-- Display : mantém lista
TempDisplay --> WeatherStation : consulta
StatsDisplay --> WeatherStation : consulta
Código Fonte (Solução — estilo pull)
| Display.java | |
|---|---|
| TempDisplay.java | |
|---|---|
Observações Didáticas
- Push vs Pull: aqui usamos pull (observers chamam getters). Em push, o Subject envia os dados no
update(payload). - Baixo acoplamento: Subject não conhece detalhes dos observers; só a interface.
- Múltiplas visões: qualquer número de observers pode ser adicionado/removido em runtime.
- Cuidados: tratar exceções de observers para não interromper a notificação; evitar leaks (detach) e atenção a concorrência se multi-thread.