|
|||||||||||||||||||||||||
|
|||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionAnyone who has ever worked with JavaScript for any amount of time should be familiar with the task of creating custom JavaScript objects. People who are not familiar with OOP in JavaScript can read a brief introduction about it here. This article deals with the implementation of the Observer pattern using JavaScript. A brief introduction to JavaScriptJavaScript is a prototype-based scripting language (originally called LiveScript) with a syntax loosely based on C, developed by Netscape Communications, for use with the Navigator browser. Like C, the language has no input or output constructs of its own. Where C relies on standard I/O libraries, the JavaScript engine relies on a host environment into which it is embedded. This scripting language accommodates what other languages might call procedures, subroutines, and functions, all in one type of structure: the custom function. One major use of web-based JavaScript is to interact with the Document Object Model (DOM) of a web page to perform tasks not possible using HTML alone. JScript is the Microsoft equivalent of Netscape's JavaScript, for use with Microsoft's Internet Explorer. Create a custom object in JavaScriptCreating a new JavaScript object consists of two steps. First, you need to create a function whose name will be the name of the new class. This function is typically referred to as a constructor. Second, you have to create as instance of the object using the function Person( name, surname )
{
this.name = name;
this.surname = surname;
}
var salvo = new Person( ‘Salvatore’, ‘Vetro’ );
How can you add a method to an object?In JavaScript, every object that can be created by calling a constructor function has an associated prototype property. The syntax for adding a new method is: customeObject.prototype.newMethodName = function;
// Specific case
Person.prototype.Speak = function(){...}
If you add a method to the prototype for an object, then all objects created with that object's constructor function will have that new method. Note that function NewObject()
{
alert("I am a new object.");
}
NewObject.prototype =
{
alert1: function(str){alert(str);}, //new method
name: 'As you want', //new property
alert2: function(){alert("Bye.");} //new method
};
var newObject = new NewObject();
newObject.alert1("Ciao");
newObject.name;
newObject.alert2();
Each time your script attempts to read or write a property of an object, JavaScript follows a specific sequence in search of a match for the property name. The sequence is as follows:
Observer Design Pattern class diagramThe Observer design pattern defines a one-to-many dependency between a subject object and any number of observer objects, so that when the subject object changes state, all its observer objects are notified and updated automatically.
Observer Design Pattern sequence diagramThe following interaction diagram illustrates the collaborations between a Subject and two Observers:
The Observer object that initiates the change request postpones its update until it gets a notification from the Subject. What are we going to do?Now you know what the Observer design pattern is and how you can create custom objects using JavaScript. As you can see in the class diagram, you have to define two methods ( Count - Add - GetAt - Clear - RemoveAt - Insert - IndexOf - LastIndexOf. function ArrayList()
{
this.aList = []; //initialize with an empty array
}
ArrayList.prototype.Count = function()
{
return this.aList.length;
}
ArrayList.prototype.Add = function( object )
{
//Object are placed at the end of the array
return this.aList.push( object );
}
ArrayList.prototype.GetAt = function( index ) //Index must be a number
{
if( index > -1 && index < this.aList.length )
return this.aList[index];
else
return undefined; //Out of bound array, return undefined
}
ArrayList.prototype.Clear = function()
{
this.aList = [];
}
ArrayList.prototype.RemoveAt = function ( index ) // index must be a number
{
var m_count = this.aList.length;
if ( m_count > 0 && index > -1 && index < this.aList.length )
{
switch( index )
{
case 0:
this.aList.shift();
break;
case m_count - 1:
this.aList.pop();
break;
default:
var head = this.aList.slice( 0, index );
var tail = this.aList.slice( index + 1 );
this.aList = head.concat( tail );
break;
}
}
}
ArrayList.prototype.Insert = function ( object, index )
{
var m_count = this.aList.length;
var m_returnValue = -1;
if ( index > -1 && index <= m_count )
{
switch(index)
{
case 0:
this.aList.unshift(object);
m_returnValue = 0;
break;
case m_count:
this.aList.push(object);
m_returnValue = m_count;
break;
default:
var head = this.aList.slice(0, index - 1);
var tail = this.aList.slice(index);
this.aList = this.aList.concat(tail.unshift(object));
m_returnValue = index;
break;
}
}
return m_returnValue;
}
ArrayList.prototype.IndexOf = function( object, startIndex )
{
var m_count = this.aList.length;
var m_returnValue = - 1;
if ( startIndex > -1 && startIndex < m_count )
{
var i = startIndex;
while( i < m_count )
{
if ( this.aList[i] == object )
{
m_returnValue = i;
break;
}
i++;
}
}
return m_returnValue;
}
ArrayList.prototype.LastIndexOf = function( object, startIndex )
{
var m_count = this.aList.length;
var m_returnValue = - 1;
if ( startIndex > -1 && startIndex < m_count )
{
var i = m_count - 1;
while( i >= startIndex )
{
if ( this.aList[i] == object )
{
m_returnValue = i;
break;
}
i--;
}
}
return m_returnValue;
}
Well done! Now you can create both the Observer class and the Subject class of the Observer design pattern. Observer class of the Observer Design PatternYou just have to define the method function Observer()
{
this.Update = function()
{
return;
}
}
Subject class of the Observer Design PatternOK, let's go define the three main methods: function Subject()
{
this.observers = new ArrayList();
}
Subject.prototype.Notify = function( context )
{
var m_count = this.observers.Count();
for( var i = 0; i < m_count; i++ )
this.observers.GetAt(i).Update( context );
}
Subject.prototype.AddObserver = function( observer )
{
if( !observer.Update )
throw 'Wrong parameter';
this.observers.Add( observer );
}
Subject.prototype.RemoveObserver = function( observer )
{
if( !observer.Update )
throw 'Wrong parameter';
this.observers.RemoveAt(this.observers.IndexOf( observer, 0 ));
}
Inheritance in JavaScriptThere are some methods to simulate inheritance using JavaScript. A very simple way is to define a simple method called function inherits(base, extension)
{
for ( var property in base )
{
try
{
extension[property] = base[property];
}
catch( warning ){}
}
}
A simple implementationNow you need to implement a client so that you can attach observers to the concrete subject. For example, you could create a simple application that defines a main checkbox as observable and some checkboxes as observers. When the concrete subject will change its own state, it is going to notify what happened to the observers. Any observer being decoupled from the subject will manage, independently of each other, the notification. /************* Concrete Subject *************/
var mainCheck = document.createElement("INPUT");
mainCheck.type = 'checkbox';
mainCheck.id = 'MainCheck';
inherits(new Subject(), mainCheck)
mainCheck["onclick"] = new Function("mainCheck.Notify(mainCheck.checked)");/**************** Observer ****************/
var obsCheck1 = document.createElement("INPUT");
var obsCheck2 = document.createElement("INPUT");
obsCheck1.type = 'checkbox';
obsCheck1.id = 'Obs1';
obsCheck2.type = 'checkbox';
obsCheck2.id = 'Obs2';
inherits(new Observer(), obsCheck1)
inherits(new Observer(), obsCheck2)
obsCheck1.Update = function(value)
{
this.checked = value;
}
obsCheck2.Update = function(value)
{
this.checked = value;
//Add ........
}
mainCheck.AddObserver(obsCheck1);
mainCheck.AddObserver(obsCheck2);
Enclosed example
CollaborationThis article could be improved. Please contact me for any suggestions.
| ||||||||||||||||||||||||