segunda-feira, 14 de maio de 2012

Javascript uma implementação do padrão observer


Já ouviu falar de design patterns?
Conhece o padrão observer?
 Leia:
 http://www.dofactory.com/Patterns/PatternObserver.aspx ,
 http://en.wikipedia.org/wiki/Observer_pattern

Muitas vezes precisamos recorrer aos design patterns para resolver alguns problemas
comuns do nosso dia a dia.

Existem muitos tipos de implementações desses designs e muitas vezes, alguns não
se adequam às necessidades reais.

Temos que ter em mente o seguinte:
1 compreender o problema;
2 entender o design pattern;
3 entender como o padrão resolverá o problema.

Vamos ver uma implementação do padrão Observer em javascript.


/** ----------------------------------------------------------------------------
 * Implementacao de um observer (singleton)
 * Ex:
 *      var a = {}, b={}, c={}, obs=Observer.getInstance();
 *      obs.addObserver('notifyA',a,function(target){console.log(target)})
 *      obs.addObserver('notifyB',b,function(target){console.log(target)})
 *      obs.addObserver('notifyC',c,function(target){console.log(target)})
 *
 *      obs.notifyAll();       // notifica todos
 *      obs.notify('notifyB'); // notifica os objetos que possuem o evento 'notifyB'
 *      obs.notifyObj(c);      // notifica um objeto especifico
 *
 * @return {*}
 * @constructor
 */
function Observer(){
    var slf=Observer;
    // singleton pattern
    if(slf.instance) return slf.instance;
    slf.instance=this;
    var _observers={},
        _getSizeOfObservers=function(){return Object.keys(_observers).length;};
    /**
     * Adiciona um observer para um objeto passado.
     * @param {String} name   Nome do evento
     * @param {Object} obj    Objeto que observara o evento
     * @param {Function} func Callback do evento
     */
    this.addObserver=function(name, obj, func){
        if(name && typeof(obj) == "object" && typeof(func)=="function" ){
            if(!obj.gid) obj.gid=Object.gid();
            name='%ev-'+name+'%id-'+obj.gid+'%len-'+_getSizeOfObservers();
            _observers[name]={obj:obj,func:func};
        }
    };
    /**
     * Remove um observer
     * @param {String} name Nome do evento
     * @param {Object} obj  Objeto que esta na lista de observers
     */
    this.removeObserver=function(name,obj){
        if(name && typeof(obj) == "object" ){
            if(!obj.gid) return;
            name='%ev-'+name+'%id-'+obj.gid;
            for(var i in _observers){
                if(i.indexOf(name)>-1)   delete _observers[i];
            }
        }
    };
    /**
     * Notifica todos os elementos que estao na lista de _observers
     */
    this.notifyAll=function(){
        for(var i in _observers)
            if(_observers[i].func) _observers[i].func(_observers[i].obj);
    };
    /**
     * Notifica um objeto especifico
     * @param {Object} obj
     */
    this.notifyObj=function(obj){
        for(var i in _observers)
            if(_observers[i].obj && _observers[i].obj.gid == obj.gid)
                _observers[i].func(_observers[i].obj);
    };
    /**
     * Notifica os objetos que aguardam um evento qualquer
     * @param {String} name Nome do evento
     */
    this.notify=function(name){
        for(var i in _observers)
            if(i.indexOf(name)>-1 && _observers[i].obj)
                _observers[i].func(_observers[i].obj);
    };
}
    /**
     * Retorna a instancia (singleton)
     * @return {Observer}
     */
    Observer.getInstance=function(){
        if(this.instance) return this.instance;
        return new Observer();
    };


Note que é uma simples implementação onde o subject é inserido em uma lista
de observers no objeto Observer, mas que serve muito bem ao propósito.

Mas não segue o padrão apresentado!
Não mesmo, mas temos todos os elementos envolvidos agindo e reagindo conforme
esperado no padrão.

Nenhum comentário:

Postar um comentário