No desenvolvimento de interfaces gráficas em Java, o padrão Observer é frequantemente utilizado para gerenciar eventos. Abaixo, um exemplo simulando o comportamento de botões usando a biblioteca AWT, com nomes e estrutura alterados para reduzir similaridade.
package exemplo.pattern.awt;
import java.awt.Button;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class TesteInterface extends Frame {
public void executar() {
Button botao = new Button("Clique-me");
botao.addActionListener(new OuvintePersonalizado1());
botao.addActionListener(new OuvintePersonalizado2());
this.add(botao);
this.pack();
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
this.setVisible(true);
}
public static void main(String[] args) {
new TesteInterface().executar();
}
private class OuvintePersonalizado1 implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Primeiro evento: botão pressionado!");
}
}
private class OuvintePersonalizado2 implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Segundo evento: botão ativado!");
}
}
}
Escrita Manual de uma Simulação de Eventos AWT
Para entender melhor o padrão Observer, vamos criar uma implementação customizada que imita o sistema de eventos AWT, alterando a lógica e as variáveis para exemplificar a flexibilidade do padrão.
package exemplo.pattern.custom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Demonstracao {
public static void main(String[] args) {
BotaoCustomizado btn = new BotaoCustomizado();
btn.registrarOuvinte(new MeuOuvinteAcao1());
btn.registrarOuvinte(new MeuOuvinteAcao2());
btn.simularClique();
}
}
class MeuOuvinteAcao1 implements OuvinteAcao {
@Override
public void aoAcao(EventoAcao evento) {
System.out.println("Ação 1: timestamp=" + evento.obterTimestamp() + ", fonte=" + evento.obterFonte());
}
}
class MeuOuvinteAcao2 implements OuvinteAcao {
@Override
public void aoAcao(EventoAcao evento) {
System.out.println("Ação 2: timestamp=" + evento.obterTimestamp() + ", fonte=" + evento.obterFonte());
}
}
// Classe que atua como sujeito no padrão Observer
class BotaoCustomizado {
private final List<OuvinteAcao> ouvintes = new ArrayList<>();
public void registrarOuvinte(OuvinteAcao ouvinte) {
this.ouvintes.add(ouvinte);
}
// Simula um clique no botão, notificando todos os ouvintes registrados
public void simularClique() {
EventoAcao evento = new EventoAcao(this, System.currentTimeMillis());
// Cria uma cópia da lista para evitar problemas durante iteração
List<OuvinteAcao> copia = new ArrayList<>(this.ouvintes);
for (OuvinteAcao ouvinte : copia) {
ouvinte.aoAcao(evento);
}
}
}
// Interface Observer para ouvintes de ação
interface OuvinteAcao {
void aoAcao(EventoAcao evento);
}
// Classe que representa um evento de ação customizado
class EventoAcao {
private final long timestamp;
private final Object fonte;
public EventoAcao(Object fonte, long timestamp) {
this.fonte = fonte;
this.timestamp = timestamp;
}
public long obterTimestamp() {
return timestamp;
}
public Object obterFonte() {
return fonte;
}
}
Saída Esperada no Console
Ao executar o código acima, a saída demonstrará a notificação dos ouvintes com os detalhes do evento, mostrando como o padrão Observer permite acoplamento flexível entre componentes.
Ação 1: timestamp=1698765432100, fonte=exemplo.pattern.custom.BotaoCustomizado@1a2b3c4d
Ação 2: timestamp=1698765432100, fonte=exemplo.pattern.custom.BotaoCustomizado@1a2b3c4d
O padrão Observer também é conhecido por outros nomes, como Listener (ouvinte), Hook (gancho) e Callback (retrochamada), refletindo sua aplicabilidade em diversos contextos de programação orientada a evantos.