Padrão Observer
Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 68 de 87.
O Observer Pattern é um padrão de projeto comportamental que estabelece uma relação de um-para-muitos entre objetos. Quando um objeto (o sujeito) muda de estado, todos os seus dependentes (os observadores) são notificados e atualizados automaticamente. Pense nisso como uma assinatura de newsletter — os assinantes recebem atualizações sempre que um novo conteúdo é publicado.
O padrão envolve dois componentes principais: um sujeito que mantém uma lista de observadores e os notifica sobre mudanças, e observadores que definem um método de atualização para responder a notificações:
import java.util.ArrayList;
import java.util.List;
interface Observer {
void update(String message);
}
class NewsPublisher {
private List<Observer> subscribers = new ArrayList<>();
public void subscribe(Observer observer) {
subscribers.add(observer);
}
public void unsubscribe(Observer observer) {
subscribers.remove(observer);
}
public void publish(String news) {
for (Observer subscriber : subscribers) {
subscriber.update(news);
}
}
}
class EmailSubscriber implements Observer {
private String email;
public EmailSubscriber(String email) {
this.email = email;
}
public void update(String message) {
System.out.println("Email to " + email + ": " + message);
}
}Quando o publicador lança notícias, todos os assinantes são notificados automaticamente:
NewsPublisher publisher = new NewsPublisher();
publisher.subscribe(new EmailSubscriber("alice@mail.com"));
publisher.subscribe(new EmailSubscriber("bob@mail.com"));
publisher.publish("Breaking news!");
// Saída:
// E-mail para alice@mail.com: Breaking news!
// E-mail para bob@mail.com: Breaking news!O Padrão Observer promove o baixo acoplamento — o sujeito não precisa conhecer as classes concretas de seus observadores, apenas que eles implementam a interface Observer. Isso torna fácil adicionar novos tipos de observadores sem modificar o sujeito.
Desafio
FácilVamos construir um sistema de alerta de preços de ações usando o Observer Pattern! Você criará um sistema onde um ticker de ações notifica múltiplos investidores sempre que o preço da ação muda, permitindo que cada investidor reaja às atualizações de preço à sua maneira.
Você organizará seu código em quatro arquivos:
Observer.java: Defina a interfaceObserverque todos os investidores implementarão. Ela deve declarar um único métodoupdate(String stockName, double price)que os observadores usam para receber notificações sobre mudanças de preço.StockTicker.java: Crie a classe sujeito que mantém uma lista de observadores e os notifica sobre mudanças de preço. SeuStockTickerdeve ter:Um campo String privado para o nome da ação (definido via construtor).
Um campo double privado para o preço atual (inicialmente 0).
Uma lista privada para armazenar os observadores inscritos.
Um método
subscribe(Observer observer)que adiciona um observador à lista.Um método
unsubscribe(Observer observer)que remove um observador da lista.Um método
setPrice(double price)que atualiza o preço e então notifica todos os observadores chamando seu métodoupdatecom o nome da ação e o novo preço.Investors.java: Crie dois tipos diferentes de investidores que implementam a interfaceObserver:DayTrader- possui um campo de nome privado definido via construtor. Quando atualizado, imprime[name] received alert: [stockName] is now $[price] - Making quick trade!LongTermInvestor- possui um campo de nome privado definido via construtor. Quando atualizado, imprime[name] received alert: [stockName] is now $[price] - Holding steady.Formate o preço com duas casas decimais.
Main.java: Reúna seu sistema de observadores! Você receberá três entradas: o nome da ação (String), a primeira atualização de preço (double) e a segunda atualização de preço (double).Crie um
StockTickercom o nome da ação fornecido. Crie umDayTraderchamado"Alice"e umLongTermInvestorchamado"Bob", e inscreva ambos no ticker.Defina o preço para o primeiro valor de entrada (todos os observadores são notificados). Em seguida, cancele a inscrição de Alice. Por fim, defina o preço para o segundo valor de entrada (apenas Bob deve ser notificado desta vez).
Você receberá três entradas em ordem: nome da ação (String), primeiro preço (double), segundo preço (double).
Este desafio demonstra o poder do Observer Pattern: o StockTicker não sabe nada sobre os tipos específicos de investidores — ele apenas sabe que eles implementam Observer. Quando você cancela a inscrição de Alice, ela para de receber atualizações enquanto Bob continua sendo notificado. Este acoplamento fraco facilita a adição de novos tipos de investidores sem alterar o ticker!
Folha de consulta
O Observer Pattern (Padrão Observador) é um padrão de projeto comportamental que estabelece uma relação de um-para-muitos entre objetos. Quando um objeto (o subject) muda de estado, todos os seus dependentes (os observers) são notificados e atualizados automaticamente.
O padrão envolve dois componentes principais:
- Subject: Mantém uma lista de observadores e os notifica sobre mudanças
- Observers: Definem um método de atualização para responder a notificações
Estrutura básica:
import java.util.ArrayList;
import java.util.List;
interface Observer {
void update(String message);
}
class Subject {
private List<Observer> observers = new ArrayList<>();
public void subscribe(Observer observer) {
observers.add(observer);
}
public void unsubscribe(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
class ConcreteObserver implements Observer {
public void update(String message) {
// Reagir à notificação
}
}Exemplo de uso:
Subject subject = new Subject();
subject.subscribe(new ConcreteObserver());
subject.notifyObservers("State changed!");
// Todos os observadores inscritos recebem a atualizaçãoO Observer Pattern promove o acoplamento fraco (loose coupling)—o subject não precisa conhecer as classes concretas de seus observers, apenas que eles implementam a interface Observer. Isso facilita a adição de novos tipos de observadores sem modificar o subject.
Experimente você mesmo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Ler as entradas
String stockName = scanner.nextLine();
double firstPrice = scanner.nextDouble();
double secondPrice = scanner.nextDouble();
// TODO: Criar um StockTicker com o nome da ação fornecido
// TODO: Criar um DayTrader chamado "Alice"
// TODO: Criar um LongTermInvestor chamado "Bob"
// TODO: Inscrever tanto Alice quanto Bob no ticker
// TODO: Definir o preço como firstPrice (ambos os observadores são notificados)
// TODO: Cancelar a inscrição de Alice
// TODO: Definir o preço como secondPrice (apenas Bob é notificado)
scanner.close();
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosCampos (Atributos)Método ConstrutorSobrecarga de ConstrutorRecapitulação - Calculadora Simples4Herança
Herança Básica (extends)A Palavra-chave superSobrescrita de Método (@Override)Encadeamento de ConstrutoresA Classe ObjectHerança Simples e MultinívelPor que não há Herança Múltipla de ClassesRecapitulação - Hierarquia de Funcionários7Métodos Especiais e a Classe Object
Método toString()equals() e hashCode()Método clone()compareTo() e ComparableInterface ComparatorRecapitulação - Ordenação Personalizada2Modificadores de Acesso e Encapsulamento
Visão Geral dos Níveis de AcessoMétodos Getter e SetterOcultação de InformaçõesA Palavra-chave finalRecapitulação - Gerenciador de Conta Bancária5Polimorfismo
Fundamentos de Sobrecarga de MétodosSobrescrita de Métodos (Tempo de Execução)Upcasting e DowncastingO Operador instanceofClasses e Métodos AbstratosRecapitulação - Calculadora de Formas8Conceitos Avançados de OOP
Composição vs HerançaAgregação vs ComposiçãoClasses Internas, Aninhadas e AnônimasEnums e Métodos de EnumRecords (Java 16+)Classes Seladas (Java 17+)11Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão BuilderPadrão ObserverPadrão Strategy3Propriedades de Classe e Membros Estáticos
Variáveis de Instância vs EstáticasMétodos EstáticosBlocos EstáticosConstantes (static final)Recapitulação - Contador e Utilitário6Interfaces e Classes Abstratas
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesDefault e Static em InterfacesClasses Abstratas vs InterfacesInterfaces FuncionaisRecapitulação - Sistema de Pagamento9Generics
Introdução a GenericsClasses GenéricasMétodos GenéricosParâmetros de Tipos DelimitadosWildcards (?, extends, super)Recapitulação - Container Genérico12Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Iterator