Le pattern observer en Javascript

28 Sep 2011

Il est très intéressant dans une application de pouvoir faire dialoguer des objets entre eux. Pour ce faire, il existe le pattern observer. Celui-ci permet de définir une relation entre plusieurs objets de façon à ce qu’à chaque modification (comprendre évènement) d’un objet les autres en soient informés.

Dans cet article je vais faire une première approche, en essayant de vous expliquer comment nous utilisons ce pattern dans notre projet.

Je vais essayer de faire un exemple simple. Pour commencer voici l’arborescence du projet :

Ici, nous avons donc deux classes principales observable.js et observer.js. Voici le principe de chacune d’elle :

observable.js : c’est l’objet où sont stockés tous les observers. observer.js : est une structure de base pour les objets observer (cat.observer.js et dog.observer.js dans notre cas). Y sont définit les méthodes de base d’un observer.

Observable :

La classe observable contient tous les observers (dans la variable this.observers) qui s’y sont enregistrés en utilisant la méthode register. La méthode notifyObservers permet quant à elle d’informer tous les observers enregistrés d’un évènement.

/**
 * OBSERVABLE CLASS
 * declaration de l'observable
 */
var Observable = function() {
  this.observers = new Array();
};

/**
 * fonctions de l'objet observable
 */
Observable.prototype = {

  // enregistre un observer a recevoir des notifications
  register: function(observer) {
    this.observers.push(observer);
    return this;
  },

  // envoie une notification a tous les observers enregistres
  notifyObservers: function(event, parameters) {
    $.each(this.observers, function(i, observer) {
      observer.notify(event, parameters);
    });
  }
};

Observer :

La classe observer est un patron, elle sert à définir les méthodes de base d’un observer. Ici la méthode register permet à l’observer de s’enregistrer auprès de l’observable. Une fois enregistrer l’observer peut recevoir des notifications auprès d’autres observers, mais aussi en envoyer. C’est la méthode notifyObserver qui s’en charge.

/**
 * OBSERVER CLASS
 * declaration de l'observer
 */
var Observer = function() {
  this.observers = new Array();
};

/**
 * fonctions de l'objet observer
 */
Observer.prototype = {
  register: function(observable) {
    this.observable = observable;
    this.notifyMe();

    return this;
  },

  notifyMe: function() {
    this.observable.register(this);
  },

  notifyObservers: function(event, parameters) {
    this.observable.notifyObservers(event, parameters);
  },

  notify: function(event, parameters) {
    return this;
  }
};

Exemple :

Maintenant, nous allons définir deux observers qui hériteront de la classe Observer.

Commençons par définir la structure de base :

var CatObserver = function($el) {

  var base = this;

  base.init = function() {};

  base.notify = function(event, parameters) {};

  return base;
};

extend(CatObserver, Observer);

Ici, nous avons une classe, CatObserver, implémentant deux méthodes, init() et notify(event, parameters). Dans la méthode init, nous allons pouvoir définir des évènements qui enverront des messages de notifications à tous les observers. Puis, la méthode notify, se chargera de recevoir les notifications envoyées plus tôt.

Un exemple concret de cette implémentation :

base.init = function() {
  $('.crier', $el).bind('click', function() {
    base.notifyObservers('chat.crier');
  });
  $('.courir', $el).bind('click', function() {
    base.notifyObservers('chat.courir');
  });
};

Deux évènements sont capturés. Chacun retourne une demande de notification de la part de l’observable avec un nom d’évènement bien défini (paramètre event).

base.notify = function(event, parameters) {
    switch(event) {
      case 'chat.crier':
        $('.dialog', $el).text('Le chat vient de miauler.');
        break;
      case 'chat.courir':
        $('.dialog', $el).text('Le chat se sauve en courant.');
        break;
      case 'dog.crier':
        $('.dialog', $el).text('Le chat prend peur.');
        break;
    }
  };

Chaque évènement auquel doit réagir l’observer est à définir ici. Prenons un exemple ici, si CatObserver a notifié qu’il a crié alors l’élément possédant la classe .dialog prendra comme valeur ‘Le chat vient de miauler’.

Le plus simple c’est de vous faire une petite démonstration.

N’hésitez pas à faire des retours, et merci à Sébastien Rogier qui s’est chargé du développement du pattern observer dans notre application.


Commentaires

comments powered by Disqus