
Observer em Java
O Observer é um padrão de projeto comportamental que permite que um objeto notifique outros objetos sobre alterações em seu estado.
O padrão Observer fornece uma maneira de assinar e cancelar a assinatura desses eventos para qualquer objeto que implemente uma interface de assinante.
Complexidade:
Popularidade:
Exemplos de uso: O padrão Observer é bastante comum no código Java, especialmente nos componentes da interface de usuário. Ele fornece uma maneira de reagir a eventos que acontecem em outros objetos sem acoplamento às suas classes.
Aqui estão alguns exemplos do padrão nas principais bibliotecas Java:
-
java.util.Observer
/java.util.Observable
(raramente usado no mundo real) - Todas as implementações de
java.util.EventListener
(praticamente em todos os componentes Swing) -
javax.servlet.http.HttpSessionBindingListener
-
javax.servlet.http.HttpSessionAttributeListener
-
javax.faces.event.PhaseListener
Identificação: O padrão pode ser reconhecido por métodos de assinatura, que armazenam objetos em uma lista e por chamadas para o método de atualização emitido para objetos nessa lista.
Assinatura do evento
Neste exemplo, o padrão Observer estabelece colaboração indireta entre objetos de um editor de texto. Sempre que o objeto Editor
é alterado, ele notifica seus assinantes. EmailNotificationListener
e LogOpenListener
reagem a essas notificações executando seus comportamentos principais.
As classes de assinante não são acopladas à classe do editor e podem ser reutilizadas em outras aplicações, se necessário. A classe Editor
depende apenas da interface abstrata do assinante. Isso permite adicionar novos tipos de assinantes sem alterar o código do editor.
publisher
publisher/EventManager.java: Publicador básico
package refactoring_guru.observer.example.publisher;
import refactoring_guru.observer.example.listeners.EventListener;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EventManager {
Map<String, List<EventListener>> listeners = new HashMap<>();
public EventManager(String... operations) {
for (String operation : operations) {
this.listeners.put(operation, new ArrayList<>());
}
}
public void subscribe(String eventType, EventListener listener) {
List<EventListener> users = listeners.get(eventType);
users.add(listener);
}
public void unsubscribe(String eventType, EventListener listener) {
List<EventListener> users = listeners.get(eventType);
users.remove(listener);
}
public void notify(String eventType, File file) {
List<EventListener> users = listeners.get(eventType);
for (EventListener listener : users) {
listener.update(eventType, file);
}
}
}
editor
editor/Editor.java: Publicador concreto, rastreado por outros objetos
package refactoring_guru.observer.example.editor;
import refactoring_guru.observer.example.publisher.EventManager;
import java.io.File;
public class Editor {
public EventManager events;
private File file;
public Editor() {
this.events = new EventManager("open", "save");
}
public void openFile(String filePath) {
this.file = new File(filePath);
events.notify("open", file);
}
public void saveFile() throws Exception {
if (this.file != null) {
events.notify("save", file);
} else {
throw new Exception("Please open a file first.");
}
}
}
listeners
listeners/EventListener.java: Interface comum do observador
package refactoring_guru.observer.example.listeners;
import java.io.File;
public interface EventListener {
void update(String eventType, File file);
}
listeners/EmailNotificationListener.java: Envia emails ao receber notificações
package refactoring_guru.observer.example.listeners;
import java.io.File;
public class EmailNotificationListener implements EventListener {
private String email;
public EmailNotificationListener(String email) {
this.email = email;
}
@Override
public void update(String eventType, File file) {
System.out.println("Email to " + email + ": Someone has performed " + eventType + " operation with the following file: " + file.getName());
}
}
listeners/LogOpenListener.java: Escreve uma mensagem em um registro ao receber uma notificação
package refactoring_guru.observer.example.listeners;
import java.io.File;
public class LogOpenListener implements EventListener {
private File log;
public LogOpenListener(String fileName) {
this.log = new File(fileName);
}
@Override
public void update(String eventType, File file) {
System.out.println("Save to log " + log + ": Someone has performed " + eventType + " operation with the following file: " + file.getName());
}
}
Demo.java: Código de inicialização
package refactoring_guru.observer.example;
import refactoring_guru.observer.example.editor.Editor;
import refactoring_guru.observer.example.listeners.EmailNotificationListener;
import refactoring_guru.observer.example.listeners.LogOpenListener;
public class Demo {
public static void main(String[] args) {
Editor editor = new Editor();
editor.events.subscribe("open", new LogOpenListener("/path/to/log/file.txt"));
editor.events.subscribe("save", new EmailNotificationListener("admin@example.com"));
try {
editor.openFile("test.txt");
editor.saveFile();
} catch (Exception e) {
e.printStackTrace();
}
}
}
OutputDemo.txt: Resultados da execução
Save to log \path\to\log\file.txt: Someone has performed open operation with the following file: test.txt
Email to admin@example.com: Someone has performed save operation with the following file: test.txt