![Observateur](/images/patterns/cards/observer-mini.png?id=fd2081ab1cff29c60b499bcf6a62786a)
Observateur en Java
L’Observateur est un patron de conception comportemental qui permet à certains objets d’envoyer des notifications concernant leur état à d’autres objets.
Ce patron fournit la possibilité aux objets qui implémentent une interface de souscription, de s’inscrire et de se désinscrire de ces événements.
Complexité :
Popularité :
Exemples d’utilisation : L’observateur est assez répandu en Java, surtout dans les composants GUI. Il fournit une manière de réagir aux événements qui se produisent chez d’autres objets sans se coupler à leurs classes.
Voici quelques exemples tirés des bibliothèques principales de Java :
-
java.util.Observer
/java.util.Observable
(rarement utilisé dans le monde réel) - Toutes les implémentations de
java.util.EventListener
(pratiquement partout dans les composants Swing) -
javax.servlet.http.HttpSessionBindingListener
-
javax.servlet.http.HttpSessionAttributeListener
-
javax.faces.event.PhaseListener
Identification : Ce patron peut être reconnu dans les méthodes de souscription qui stockent des objets dans une liste et par les appels des objets de cette liste à la méthode update.
Inscription aux événements
Dans cet exemple, l’observateur établit une collaboration indirecte entre les objets d’un éditeur de texte. Chaque fois que l’objet Éditeur
est modifié, il envoie une notification à ses souscripteurs. EmailNotificationListener
et LogOpenListener
réagissent à ces notifications en exécutant leurs comportements principaux.
Les classes du souscripteur ne sont pas couplées aux classes de l’éditeur et peuvent être réutilisées dans d’autres applications si besoin. La classe Éditeur
dépend uniquement de l’interface abstraite du souscripteur. Ainsi nous pouvons ajouter de nouveaux types de souscripteurs sans modifier le code de l’éditeur.
publisher
publisher/EventManager.java: Diffuseur de base
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: Diffuseur concret suivi par d’autres objets
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 Observateur commune
package refactoring_guru.observer.example.listeners;
import java.io.File;
public interface EventListener {
void update(String eventType, File file);
}
listeners/EmailNotificationListener.java: Envoie des e-mails lorsqu’il reçoit une notification
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: Écrit un message dans une log lorsqu’il reçoit une notification
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: Code d’initialisation
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: Résultat de l’exécution
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