Padrão Observer
Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy. Lição 68 de 87.
O padrão Observer é um padrão comportamental de projeto que estabelece uma relação de um para muitos entre objetos. Quando um objeto (o assunto) muda de estado, todas as suas dependências (os observadores) são automaticamente notificadas e atualizadas. 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 às 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 editor publica 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 baixo acoplamento: o sujeito não precisa conhecer as classes concretas de seus observadores, apenas que eles implementam a interface Observer. Isso facilita adicionar novos tipos de observadores sem modificar o sujeito.
Desafio
FácilVamos criar um sistema de alerta de preços de ações usando o Padrão Observer! Você criará um sistema em que um ticker de ações notifica vários investidores sempre que o preço da ação muda, permitindo que cada investidor reaja às atualizações de preço à sua própria 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 usarão para receber notificações sobre mudanças de preço.StockTicker.java: crie a classe subject que mantém uma lista de observadores e os notifica sobre mudanças de preço. SeuStockTickerdeve ter:Um campo privado do tipo String para o nome da ação (definido pelo construtor).
Um campo privado do tipo double 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, em seguida, notifica todos os observadores chamando o métodoupdatedeles com o nome da ação e o novo preço.Investors.java: crie dois tipos diferentes de investidores que implementam a interfaceObserver:DayTrader- tem um campo privado para o nome, definido pelo construtor. Quando atualizado, imprime[name] received alert: [stockName] is now $[price] - Making quick trade!LongTermInvestor- tem um campo privado para o nome, definido pelo 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 como o primeiro valor de entrada (todos os observadores serão notificados). Em seguida, cancele a inscrição de Alice. Por fim, defina o preço como o segundo valor de entrada (somente Bob deverá ser notificado desta vez).
Você receberá três entradas nesta ordem: nome da ação (String), primeiro preço (double), segundo preço (double).
Este desafio demonstra o poder do Padrão Observer: 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. Esse baixo acoplamento facilita a adição de novos tipos de investidores sem alterar o ticker!
Experimente você mesmo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Ler entradas
String stockName = scanner.nextLine();
double firstPrice = scanner.nextDouble();
double secondPrice = scanner.nextDouble();
// TODO: Crie um StockTicker com o nome da ação fornecido
// TODO: Crie um DayTrader chamado "Alice"
// TODO: Crie um LongTermInvestor chamado "Bob"
// TODO: Inscreva Alice e Bob no ticker
// TODO: Defina o preço como firstPrice (ambos os observadores são notificados)
// TODO: Cancele a inscrição de Alice
// TODO: Defina 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 IteratorPratique por conta própria: Compilador de Java online