Le modèle observateur est un pattern de conception fréquemment employé, en particulier dans les interfaces graphiques (GUI) et les architectures de publication-abonnement. Son rôle principal est de réduire le couplage entre les entités observées et les observateurs, minimisant ainsi leurs interdépendances.
Définition : Il établit une relation un-à-plusierus entre objets, de sorte que lorsqu'un objet change d'état, tous les objets qui en dépendent sont notifiés et mis à jour automatiquement.
Scénarios d'utilisation :
- Situations impliquant des comportements corrélés, où les interactions sont dissociables et non structurelles.
- Environnements avec des déclenchements d'événements à plusieurs niveaux.
- Échanges de messages inter-systèmes, tels que les files d'attente de messages ou les bus d'événements.
Illustrons ceci avec un exemple concret : les feux de circulation pour traverser une route. Ici, les véhicules et les piétons agissent comme observateurs, tandis que le feu rouge est l'entité observée. Du point de vue des piétons, lorsque le feu rouge s'allume (le feu vert pour les véhicules s'allume aussi), les véhicules avancent et les piétons s'arrêtent.
Implémentation du code
D'abord, définissons la classe abstraite pour les observateurs :
/**
* Classe abstraite pour les observateurs
*/
public abstract class Observateur {
protected abstract void onChangement();
}
Ensuite, créons une classe concrète pour un véhicule :
/**
* Observateur : véhicule
*/
public class Vehicule extends Observateur {
@Override
protected void onChangement() {
System.out.println("Le feu vert est allumé, je peux avancer");
}
}
Puis, une classe pour les piétons :
/**
* Observateur : piéton
*/
public class Pieton extends Observateur {
@Override
protected void onChangement() {
System.out.println("Le feu rouge est allumé, je dois attendre");
}
}
Passons à l'entité observée, qui gère une collection d'boservateurs :
/**
* Entité observée : feu de signalisation
*/
public class SujetObserve {
private List<Observateur> observateurs = new ArrayList<>();
// Ajouter un observateur
public void ajouterObservateur(Observateur obs) {
observateurs.add(obs);
}
// Supprimer un observateur
public void supprimerObservateur(Observateur obs) {
observateurs.remove(obs);
}
// Méthode appelée lors d'un changement d'état
public void etatModifie() {
for (Observateur obs : observateurs) {
obs.onChangement();
}
}
}
Voici une classe de test pour illustrer le fonctionnement :
/**
* Test du modèle observateur
*/
public class TestObservateur {
public static void main(String[] args) {
// Créer des observateurs
Observateur vehicule = new Vehicule();
Observateur pieton = new Pieton();
// Créer l'entité observée
SujetObserve feuSignalisation = new SujetObserve();
// Enregistrer les observateurs
feuSignalisation.ajouterObservateur(vehicule);
feuSignalisation.ajouterObservateur(pieton);
// Déclencher un changement d'état
feuSignalisation.etatModifie();
}
}
Cette approche stocke une liste d'observateurs dans l'entité observée, qui les notifie tous lors d'un changement. Cependant, avec un grand nombre d'observateurs, cela peut entraîner des problèmes de performance. Il convient donc de l'adapter en fonction du contexte, en intégrant par exemple des mécanismes d'optimisation comme l'utilisation de pools de threads.