As above, let us first look at the definition of the
Observer pattern.
(1) Concept
The Observer pattern defines a relationship between objects
so that when one changes its state, all the others are notified accordingly. Generally,
you are suggested to consider leveraging the Observer pattern under the
following conditions.
·
When an abstract model contains two parts, one depending on the
other, you need to seal these twos independently in order to change and reuse
them respectively and independently.
·
When you want to change an object then in the meantime you have
to change other objects, but do not know how many objects need the related
change.
·
When an object has to notify other objects, but it cannot suppose
who the other objects are. In other words, you do not hope that these objects
are closely coupled.
(2) Example
Underneath, we are going to apply the Observer pattern to a
simple yet typical JavaScript event handling mechanism. First, we need to do
some preparation, namely expanding the Array object with two methods (i.e. indexOf and removeAt below), as shown
in Listing 12.
Listing 12 - Expand the Array object
//expand the properties of the destination object
//, copy all the properties of the source object
//, to the destination
Object.extend=function(destination,source){
for(property in source){
destination[property]=source[property];
}
return destination;
}
// expand the built-in Array object
Object.extend(Array.prototype,{
//retrieve the object in the array
indexOf: function (object){
for(var i=0,1ength=this.length; i<length; i++)
if(this[i]==object) return i;
return -1;
},
//remove the specified element in the array
removeAt: function (index){
if(index<0 || index>=this.length) return null;
switch(index){
case 0:
return this.shift();
break;
case this.length -1:
return this.pop();
break;
default:
var head=this.s1ice(0,index);
var tail=this.s1ice(index+1);
var ele=this[index];
this=head.concat(tail);
return ele;
break;
}
}
});
Next, define two classes, i.e. Observer and Subject. The
code related to the Observer class is shown below:
//the Observer class
function Observer(){}
object.extend(Observer.prototype, {
//note that the later instantiation Observer
will override this Update method
Update:function(){
return;
}
});
The code related to the Subject class is as follows.
Listing 13
// the Subject class
function Subject(){}
Object.extend(Subject.prototype,{
//an array of the Observer objects
observers:[],
// notify per Observer object to execute the Update method
notify:function(context){
for(var i=0; i<this.observers.length; i++)
this.observers[i].Update(context);
},
//add a new Observer
addObserver:function(observer) {
if(!observer.Update)
throw new Error(“addObserver error!”);
this.observers.push(observer);
},
//delete the existing Observer
removeObserver:function(Observer) {
if(!observer.Update)
throw new Error(“removeObserver error!”);
this.observers.removeAt(this.observers.indexOf(observer));
},
});
OK, for now we have defined all the objects relating to the Observer
pattern. The following lists the steps to carry out the Observer pattern:
·
Establish an instantiation of the Subject class.
·
Establish several instantiations of the Observer object,
overriding their Update methods respectively.
·
Subscribe all the Observer objects to the Subject object.
·
Send out a notice through the Subject object, when the Observers
objects are subscribed to the Subject object will execute their Update methods respectively.
·
If you need to cancel a certain Observer object's subscription
for the Subject object, you can invoke the removeObserver
method.
Finally, we are to set up an example to show you the application
of the Observer pattern, as well as the objects defined above. First, Establish
a Subject object and define a publishEvent method for
it.
Listing 14
//Create a new Subject object
var concreteSubject=new Subject();
// define a new publishEvent method with which to
notify all the Observer of the related data
concreteSubject.publishEvent=function(data){
document.write(“published:”+data);
this.notify(data);
}
Then, establish two Observer objects; overlay their Update methods respectively.
Listing 15
// create a new Subject object
var concreteSubject=new Subject();
// define a new publishEvent method with which to
notify all the Observer of the related data
concreteSubject.publishEvent=function(data) (
document.write(“published:”+data);
this.notify(data);
}
// Create a new Observer object and override its
Update method
var concreteObserverl=new Observer();
concreteObserverl.Update=function(data){
document.write(“concreteObserverl
received:”+data);
}
//subscribe concreteObserverl to concreteSubject
concreteSubject.addObserver(concreteObserverl);
// create the second Observer object and override
its Update method
var concreteObserver2=new Observer();
concreteObserver2.Update=function(data){
document.write(“concreteObserver2
received:”+data);
}
//subscribe concreteObserver2 to concreteSubject
concreteSubject.addObserver(concreteObserver2);
Now, let us carry out the publishEvent
method of the concreteSubject object, sending out a
notice.
Listing 16
concreteSubject.publishEvent(“msg”);
At this time, the application will output the following.
Listing 17
published:msg
concreteObserverl received:msg
concreteObserver2 receired:msg
Such results proved that concreteObserverl and
concreteObserver both received a notice from the concreteSubject object. Next, you
can use the removeObserver method to cancel a subscription for the
concreteSubject object.
Listing 18
concreteSubject.removeObserver(concreteObserver2);
Again send out a notice:
Listing 19
concreteSubject.publishEvent(“msg”);
This time, only concreteObserver receives the notice and the
application will output the following.
Listing 20
published:msg
concreteObserver1 receired:msg
Using the Observer pattern can implement the typical event
mechanism in the JavaScript environment. Those who are acquainted with the Ajax development may know of the two famous client-side Ajax frameworks--Prototype
and Dojo. In fact, the two frameworks both adopt the similar
means herein to introduce their respective event mechanisms. Readers who have
interests with this can study further.