martedì, ottobre 10, 2006

Observer Subscriber in Base

I was playing with Dean Edwards Base and I would to implement
the Observer Subscriver pattern.
I wrote this Observer implementation:


//Clone method
Base.prototype.clone=function(){return new Base(this);}

//Define the Observer class
var Observer= Base.extend({
subscribe:function (obj,evt){
//if(!this["on"+evt])this["on"+evt]=[];
if(typeof(this["on"+evt]) === "undefined")this["on"+evt]=[];
this["on"+evt].push(obj);
},
raise:function (evt){
var list=this["on"+evt];

if(list){
var max=list.length;
for(var i=0;i<max;i++)
//if(list[i].update)list[i].update();
if(typeof(list[i].update)!=="undefined")list[i].update();
}
}
});
//Define the subscriber class
var Subscriber = Base.extend({update:function(){alert("update() must be implemented");}});


and this little test

/*Simple example of implementation*/

//Istantantiate a Observer
var observer= new Observer();

//Define a Event
observer.evt=function(){
//do stuff
this.raise("evt");
}

//Istantiate a Subscriber
var subscriber1=new Subscriber();
//Clone a Subscriber
var subscriber2=subscriber1.clone();

//define a custom update function
subscriber2.update=function(){
alert("here update() was implemented");
}

//subscribe our 2 object
observer.subscribe(subscriber1,"evt");
observer.subscribe(subscriber2,"evt");

//Raise the event
observer.evt();


Base is Great, it was so simple!




Update!
As I said in the comment this wasn't a correct implementation.

A correct(I hope) is the follow implementation:

//Clone method
Base.prototype.clone=function(){return new Base(this);}

var Observer = Base.extend({
update:function(evt){
alert("update() must be defined");
}
});
var Subject = Base.extend({
observers:[],
constructor:function(){this.observers=new Array();},
registerObserver:function(obj){
this.observers.push(obj);
return obj;
},
unregisterObserver:function(obj){
if(this.observers.length>0)
var tmp=this.observers.pop();
if (tmp!==obj){
var max=this.observers.length;
for(var i=0;i<max;i++)
if(this.observers[i]===obj){this.observers[i]=tmp;break;}
}
return this;
},
notifyObserver:function(evt){
var max=this.observers.length;
for(var i=0;i<max;i++)
this.observers[i].update(evt);
}
});

And so the Test:

/*Example:*/
var subject = new Subject();
subject.x=0;
subject.add=function(){
this.x++;
this.notifyObserver();
}
var observer1 = new Observer();
var observer2 =observer1.clone();
observer1.update=function(){alert("now x is "+subject.x);}
observer2.update=function(){alert("something happened on subject")}

subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.add();
subject.unregisterObserver(observer2);
subject.add();

3 commenti:

kentaromiura ha detto...

After read this:
http://www.javaworld.com/javaworld/javaqa/2001-05/04-qa-0525-observer.html
I understand that is not a Correct implementation of Observer / Subject.
In fact in this design pattern the Subject Raise the Event, not the Observer, so I was totally wrong.

kentaromiura ha detto...

after read http://www.dustindiaz.com/javascript-publisher/

I update Observer, now you can chain , and I found a bug,solved thanks to constructor!!

here the example in the link, modified to use my 'class':


Observer.prototype.subscribe =function(who){who.registerObserver(this);return this;}

var NewYorkTimes = new Subject();
var AustinHerald = new Subject();
var SfChronicle = new Subject();

function _update(name,from){
alert('Delivery from '+from+' to '+name);
}

var Ken=new Observer;
var ChunLi=new Observer;
var Ryu=new Observer;

Ken.update=function(e){
_update("Ken",e);
}
ChunLi.update=function(e){
_update("ChunLi",e);
}
Ryu.update=function(e){
_update("Ryu",e);
}





Ken.subscribe(NewYorkTimes);

ChunLi.subscribe(AustinHerald).subscribe(SfChronicle).subscribe(NewYorkTimes);

Ryu.subscribe(AustinHerald).subscribe(SfChronicle);


NewYorkTimes.notifyObserver("NewYork Times");

SfChronicle.notifyObserver("Street Fighters Chronicle");

AustinHerald.notifyObserver("Austin Herald");

Unknown ha detto...

just followed your link from dean's base.js page. I tried your example and it helped understand even further.
Thanks.