Modèle de conception Observer en Java

Le modèle Observer est l’un des modèles de conception comportementaux. Le modèle de conception Observer est utile lorsque vous êtes intéressé par l’état d’un objet et que vous souhaitez être notifié à chaque fois qu’il y a un changement. Dans le modèle Observer, l’objet qui observe l’état d’un autre objet est appelé Observateur et l’objet observé est appelé Sujet.

Modèle de conception Observer

Selon GoF, l’intention du modèle de conception Observer est;

Définir une dépendance un-à-plusieurs entre les objets de sorte que lorsqu’un objet change d’état, tous ses dépendants sont notifiés et mis à jour automatiquement.

Sujet contient une liste d’observateurs à notifier de tout changement dans son état, il devrait donc fournir des méthodes permettant aux observateurs de s’enregistrer et de se désenregistrer. Le Sujet contient également une méthode pour notifier tous les observateurs de tout changement, et soit il peut envoyer la mise à jour tout en notifiant l’observateur, soit il peut fournir une autre méthode pour obtenir la mise à jour. L’observateur devrait avoir une méthode pour définir l’objet à surveiller et une autre méthode qui sera utilisée par le Sujet pour les notifier de toute mise à jour. Java fournit une plateforme intégrée pour implémenter le modèle Observateur avec la classe java.util.Observable et l’interface java.util.Observer. Cependant, il n’est pas largement utilisé car l’implémentation est vraiment simple et la plupart du temps, nous ne voulons pas finir par étendre une classe juste pour implémenter le modèle Observateur, car Java ne fournit pas l’héritage multiple dans les classes. Le service de messagerie Java (JMS) utilise le modèle de conception Observateur avec le modèle Médiateur pour permettre aux applications de s’abonner et de publier des données à d’autres applications. Les cadres Modèle-Vue-Contrôleur (MVC) utilisent également le modèle Observateur, où le Modèle est le Sujet et les Vues sont des observateurs qui peuvent s’enregistrer pour être informés de tout changement sur le modèle.

Exemple du Modèle Observateur en Java

Pour notre exemple de programme java utilisant le modèle observer, nous implémenterions un sujet simple et des observateurs pouvant s’inscrire à ce sujet. Chaque fois qu’un nouveau message est publié sur le sujet, tous les observateurs enregistrés seront notifiés et pourront consommer le message. En fonction des exigences du sujet, voici l’interface de sujet de base qui définit les méthodes contractuelles à implémenter par tout sujet concret.

package com.journaldev.design.observer;

public interface Subject {

	 // méthodes pour enregistrer et désenregistrer les observateurs  

	public void register(Observer obj);
	public void unregister(Observer obj);
	
	 // méthode pour notifier les observateurs du changement  

	public void notifyObservers();
	
	 // méthode pour obtenir des mises à jour du sujet  

	public Object getUpdate(Observer obj);
	
}

Ensuite, nous créerons un contrat pour l’observateur, il y aura une méthode pour attacher le sujet à l’observateur et une autre méthode à utiliser par le sujet pour notifier tout changement.

package com.journaldev.design.observer;

public interface Observer {
	
	 // méthode pour mettre à jour l'observateur, utilisée par le sujet  

	public void update();
	
	 // s'attacher avec le sujet pour observer  

	public void setSubject(Subject sub);
}

Maintenant notre contrat est prêt, procédons à l’implémentation concrète de notre sujet.

package com.journaldev.design.observer;

import java.util.ArrayList;
import java.util.List;

public class MyTopic implements Subject {

	private List observers;
	private String message;
	private boolean changed;
	private final Object MUTEX= new Object();
	
	public MyTopic(){
		this.observers=new ArrayList<>();
	}
	@Override
	public void register(Observer obj) {
		if(obj == null) throw new NullPointerException("Null Observer");
		synchronized (MUTEX) {
		if(!observers.contains(obj)) observers.add(obj);
		}
	}

	@Override
	public void unregister(Observer obj) {
		synchronized (MUTEX) {
		observers.remove(obj);
		}
	}

	@Override
	public void notifyObservers() {
		List observersLocal = null;
		 // la synchronisation est utilisée pour s'assurer qu'aucun observateur enregistré après la réception du message n'est notifié  

		synchronized (MUTEX) {
			if (!changed)
				return;
			observersLocal = new ArrayList<>(this.observers);
			this.changed=false;
		}
		for (Observer obj : observersLocal) {
			obj.update();
		}

	}

	@Override
	public Object getUpdate(Observer obj) {
		return this.message;
	}
	
	 // méthode pour poster un message sur le sujet
	public void postMessage(String msg){
		System.out.println("Message Posted to Topic:"+msg);
		this.message=msg;
		this.changed=true;
		notifyObservers();
	}

}

La mise en œuvre de la méthode pour enregistrer et désenregistrer un observateur est très simple. La méthode supplémentaire est postMessage(), qui sera utilisée par l’application cliente pour poster un message chaîne sur le sujet. Remarquez la variable booléenne pour suivre le changement d’état du sujet et utilisée pour notifier les observateurs. Cette variable est nécessaire afin que si aucune mise à jour n’a eu lieu et que quelqu’un appelle la méthode notifyObservers(), cela n’envoie pas de fausses notifications aux observateurs. Remarquez également l’utilisation de synchronisation dans la méthode notifyObservers() pour s’assurer que la notification est envoyée uniquement aux observateurs enregistrés avant que le message ne soit publié sur le sujet. Voici la mise en œuvre des observateurs qui surveilleront le sujet.

package com.journaldev.design.observer;

public class MyTopicSubscriber implements Observer {
	
	private String name;
	private Subject topic;
	
	public MyTopicSubscriber(String nm){
		this.name=nm;
	}
	@Override
	public void update() {
		String msg = (String) topic.getUpdate(this);
		if(msg == null){
			System.out.println(name+":: No new message");
		}else
		System.out.println(name+":: Consuming message::"+msg);
	}

	@Override
	public void setSubject(Subject sub) {
		this.topic=sub;
	}

}

Remarquez la mise en œuvre de la méthode update() où elle appelle la méthode getUpdate() du sujet pour obtenir le message à consommer. On aurait pu éviter cet appel en passant le message en tant qu’argument à la méthode update(). Voici un programme de test simple pour consommer notre mise en œuvre du sujet.

package com.journaldev.design.observer;

public class ObserverPatternTest {

	public static void main(String[] args) {
		//créer le sujet
		MyTopic topic = new MyTopic();
		
		//créer les observateurs
		Observer obj1 = new MyTopicSubscriber("Obj1");
		Observer obj2 = new MyTopicSubscriber("Obj2");
		Observer obj3 = new MyTopicSubscriber("Obj3");
		
		//enregistrer les observateurs auprès du sujet
		topic.register(obj1);
		topic.register(obj2);
		topic.register(obj3);
		
		//attacher l'observateur au sujet
		obj1.setSubject(topic);
		obj2.setSubject(topic);
		obj3.setSubject(topic);
		
		//vérifier si une mise à jour est disponible
		obj1.update();
		
		//envoyer maintenant un message au sujet
		topic.postMessage("New Message");
	}

}

Lorsque nous exécutons le programme ci-dessus, nous obtenons la sortie suivante.

Obj1:: No new message
Message Posted to Topic:New Message
Obj1:: Consuming message::New Message
Obj2:: Consuming message::New Message
Obj3:: Consuming message::New Message

Diagramme de classe du modèle Observer Java

Le modèle de conception Observer est également appelé modèle de publication-abonnement. Certaines de ses implémentations sont;

  • java.util.EventListener dans Swing
  • javax.servlet.http.HttpSessionBindingListener
  • javax.servlet.http.HttpSessionAttributeListener

C’est tout pour le modèle de conception Observer en Java, j’espère que vous l’avez aimé. Partagez votre amour avec des commentaires et en le partageant avec d’autres.

Source:
https://www.digitalocean.com/community/tutorials/observer-design-pattern-in-java