Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Designs Patterns : Modéle Observateur

Compatible ActionScript 2. Cliquer pour en savoir plus sur les compatibilités.

Le modéle Observateur est un mécanisme de diffusion d'évenements, il diffuse des mises à jour d'un sujet, à des écouteurs qui se sont enregistré à celui-ci.

On l'utilise pour s'occuper de la gestion de thémes visuels, dans des jeux, il permet de diffuser simplement et aisément les modifications apportées à un objet. Les écouteurs se chargeant par la suite de faire ce qu'ils veulent des informations reçues par notification.

La seule contrainte étant que les écouteurs doivent définir une méthode pour recevoir les mises à jour.

Lorsque le sujet change d'état, il appelle notifiyObs, qui lance update sur tous les observateurs de ce sujet, update peut effectuer des taches trés différentes selon les observateurs …

Présentation

Voici les class nécessaires à l'élaboration de ce Design Pattern :

  • Observateur
    • Défini les méthodes qui vont être étendues aux sujetx.
    • Stocke les observateurs du sujet.
    • Permet l'ajout, la suppression et la notification des observateurs d'un sujet.
  • IObservateur
    • Interface que les observateurs de sujets doivent implementer ( être notifié, se désabonner ).
  • Sujet
    • le sujet étends Observateur, et doit contenir dans ses méthodes des appels à la notification de ses observateurs.
  • ObservateurSujet
    • Doit implémenter IObservateur.

Implémentation

Class Observateur :

import IObservateur;
class Observateur
{
	// boolean définissant si le sujet a changé ou non.
	private var _bChanged : Boolean = false;
	// stockage des observateurs
	private var _aObservateurs : Array;
	// constructeur
	public function Observateur ()
	{
		_aObservateurs = [];
	}
	// ajouter un observateur
	public function addObs (o : IObservateur) : Boolean
	{
		if (o == null)
		{
			return false;
		}
		var l : Number = _aObservateurs.length;
		// on n'autorise qu'une seule occurence d'un observateur précis.
		// pour éviter les doubles notification.
		for (var i : Number = 0; i < l; i ++)
		{
			if (_aObservateurs [i] == o)
			{
				return false;
			}
		}
		_aObservateurs.push (o);
		return true;
	}
	// supprimer un observateur
	public function removeObs (o : IObservateur) : Boolean
	{
		var l : Number = _aObservateurs.length;
		for (var i : Number = 0; i < l; i ++)
		{
			if (_aObservateurs [i] == o)
			{
				_aObservateurs.splice (i, 1);
				return true;
			}
		}
		return false;
	}
	// notifier les observateurs
	public function notifyObs (oInfo : Object) : Void
	{
		if (oInfo == undefined)
		{
			oInfo = null;
		}
		// on évite un appel inutile si le sujet n'a pas changé
		if ( ! _bChanged)
		{
			return;
		}
		// on effectue une copie du tableau d'observateurs, pour ne notifier que ceux actuellement inscrit.
		var _aObservateursCopy : Array = _aObservateurs.slice (0);
		clearChanged ();
		var l : Number = _aObservateursCopy.length
		for (var i : Number = l - 1; i >= 0; i --)
		{
			// on lance la fonction que doivent implementer les observateurs
			_aObservateursCopy [i].update (this, oInfo);
		}
	}
	// supprimer tout les observateurs
	public function clearObs () : Void
	{
		_aObservateurs = [];
	}
	private function setChanged () : Void
	{
		_bChanged = true;
	}
	private function clearChanged () : Void
	{
		_bChanged = false;
	}
	public function hasChanged () : Boolean
	{
		return _bChanged;
	}
	public function countObs () : Number
	{
		return _aObservateurs.length;
	}
}

Interface IObservateur :

import Observateur;
interface IObservateur
{
	public function update (o : Observateur, infoObj : Object) : Void;
	public function destroy () : Void;
}

Class Sujet :

import Observateur;
class Sujet extends Observateur
{
	private var _sMsg : String;
	public function Sujet ()
	{
		_sMsg = "";
	}
	public function setMsg (s : String)
	{
		_sMsg = s;
		// on indique que l'état du sujet a changé.
		setChanged ();
		var o : Object = {
			msg : _sMsg
		}
		// on notifie les observateurs du sujet.
		notifyObs (o);
	}
}

Class ObservateurSujet :

import IObservateur;
import Sujet;
 
class ObservateurSujet implements IObservateur 
{
 
	private var _oSujet : Sujet;
	// on l'occurence du sujet lors de la creation de son observateur.
	public function ObservateurSujet (o : Sujet)
	{
		_oSujet = o;
	}
	// fonctions obligatoires, à implementer pour tout les observateurs.
	public function update (o : Observateur, oInfo : Object) : Void 
	{
		trace ("MAJ : "+oInfo.msg);
	}
	public function destroy () : Void 
	{
		_oSujet.removeObs (this);
	}
}

Usage

import Observateur;
import Sujet;
import ObservateurSujet;
// création du sujet
var oS:Sujet = new Sujet();
// création de son observateur ( sujet en argument )
var oT:Traceur = new ObservateurSujet(oS);
// on ajoute l'observateur au sujet. ( référence croisée )
oS.addObs(oT);
// on lance une notification
oS.setMsg("Je notifie à mes observateurs que j'ai changé");
/* Résultat : 
MAJ : Je notifie à mes observateurs que j'ai changé
*/

Notes

Vous pouvez adapter cela à vos besoins, par exemple, ne pas envoyer les informations de modification, mais juste indiquer que l'etat du sujet à changer, laissant ainsi à votre observateur le soin de lancer une méthode qui lui convient sur le sujet qu'il surveille.