用javaScript实现观察者模式
本文的几个第一:
第一次尝试翻译,原文来自codeproject(http://www.codeproject.com/jscript/Observer_Pattern_JS.asp)
第一次使用Windows Live Writer,beta 版.
第一次在自己的blog中写上:Flyingchen-苏州.Net俱乐部。
文章导言:
任何使用过javascript的人,不论你使用多久,都应该熟悉如何通过javascript创建自定义对象。如果你不了解OOP在JavaScript中的运用,那么你也可以看个大概。本文就是用JavaScript来实现观察者模式。
对JavaScript的大概介绍:
JavaScript是一种基于原型的教本语言(最初叫做LiveScript),有着类似C的语法。JavaScript最初开发者是美国网景公司,用于他的Navigator浏览器。和C一样,这种语言没有自己的输入或输出的构建方法。正如C依赖于标准输入/输出函数库一样,JavaScript引擎依赖于主机环境,它是一种嵌入式语言。其他语言,有的用过程调用,有的用子程序,有的是函数。JavaScript协调其他语言的实现,统一实现为:自定义函数。JavaScript一个重大的运用,就是和Web的文档结构模型(DOM)结合,而不仅仅是HTML去完成功能。JScript,和网景的JavaScript类似的,用于微软IE的教本语言。
用JavaScript创建一个用户自定义对象
创建一个JavaScript对象需要两个步骤:
第一步:你需要创建一个自定义函数,它的名字也就是这个新的对象的名字。这样一个函数类似于一个构造方法。
第二步:你需要创建一个实例。和OO语言一样,用new操作符,气候紧跟这个对象的名字和必要的参数(如果有的话)。下面这些代码演示了如何定义一个Person函数,和创建一个Person对象实例。
function Person( name, surname )
{
this.name = name;
this.surname = surname;
}
var salvo = new Person( ‘Salvatore’, ‘Vetro’ );
this指针指向当前对象,你可以用它来增加或者修改这个对象的属性。
如何在对象上添加一个方法:
In JavaScript, every object that can be created by calling a constructor function has an associated prototype property.
下面的语法用来为对象增加一个新的方法:
customeObject.prototype.newMethodName = function;
// Specific case
Person.prototype.Speak = function(){...}
如果你为一个对象的原型添加了一个新的方法,那么这个对象的实例都将拥有这个新的方法。注意这个prototype本身就是一个对象,也可以通过它的语法给它的属性和方法赋值:
function NewObject()
{
alert("I am a new object");
}
NewObject.prototype =
{
alert1:unction(str){alert(str),/new method
name:'flyingchen',
alert2:function(){alert('bye')}//new method
}
var newobject = new NewObject();
newobject.alert1(newobject.name);
newobject.alert2();
每次,当你的script试图去读或写一个对象的属性的时候,JavaScript根据下面这个明确的顺序去搜索匹配的属性的名字。这个顺序是:
-
如果当前对象这个属性已经被赋值,那么这个值就是你获取的。
-
如果属性没有被赋值,那么就要check这个属性的原型中构造方法是如何赋值的。
-
继续沿原型这个链向上,直到任一个匹配的属性被发现(已经被赋值后的),或者当这个匹配过程一直到最定层的对象。因此,如果你改变构造的原型的属性的值,并且没有在实例中改写这个属性值,那么JavaScript将把构造器当前的值返回。
观察者模式的类图:
观察者模式定义了一个被观察对象和多个观察对象之间的一对多的依赖关系。因此,被观察者状态的改变,所有观察者对象都将知道并自动更新自己的状态。
参与者:
-
Subject:
1.知道自己的观察者
2.提供一个接口能够添加和分离观察者对象
-
Observer:
1.定义一个接口,能够被subject在状态变化的时候调用
-
ConcreteSubject:
1.存放ConcreteObserver感兴趣的状态信息÷
2.当状态改变的时候,通知观察者。
-
ConcreteObserver:
1.拥有一个ConcreteSubject的引用。
2.保存一个状态信息,这个状态信息应该和subject中一致。
3.实现Observer的Update接口,以此用来保持与Subject中状态信息的协调。
协作关系:
1。当subject状态改变的时候,ConcreteSubject发送消息给观察者们。
2。ConcreteObserver在接受到消息后,可能要查询subject当前的信息。ConcreteObserver通过这些信息来改变自己的状态。
下一步做什么呢?
现在你知道了什么是观察者模式,同时你也知道了如何用JavaScript来创建对象。正如你从类图中看到的,你需要定义两个方法(Attach 和 Detach )在你的被观察者类(subject)中。为了这个目的,你需要一个结合来完成这两个操作。现在是你动手,用JavaScript写ArrayList的时候了:
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;
}
很好,现在你可以创建Observer对象和Subject对象了。
Observer Class :
function Observer()
{
this.Update = function()
{
return;
}
}
Subject Class:
下面,我们来实现Subject中的三个中的重要方法:
function Subject()
{
this.observer = 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 ));
}
JavaScript中的继承实现:
下面几个方法用JavaScript模仿继承的实现。一个简单的方法就是定义一个方法,叫做inherits。然后把“基类"的属性拷贝到"子类"中。
function inherits(base, extension)
{
for ( var property in base )
{
try
{
extension[property] = base[property];
}
catch( warning ){}
}
}
一个简单的实现:
现在你需要实现一个客户端,以便你能够给subject添加观察者。例如,你可以创建一个简单的运用,定义一个checkbox作为subject,同时再定义一些checkboxes作为观察者。当concrete subject状态改变的时候,将把消息发送给所有的观察者。
************* 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 ****************/</CODE>
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);
//代码下载
2006-8-16
posted on 2006-08-16 20:27 flyingchen 阅读(3365) 评论(14) 编辑 收藏 举报