使用JavaScript的观察者设计 Pattern

分享于 

12分钟阅读

Web开发

  繁體

介绍

任何曾经使用过JavaScript的人都应该熟悉创建定制JavaScript对象的任务。 JavaScript中不熟悉OOP的人可以在这里阅读关于它的简要介绍。 本文使用JavaScript来实现观察者 Pattern。

JavaScript简介

JavaScript是基于Prototype的脚本语言( 最初称为 LiveScript ),它是由Netscape通信开发的基于C 语言开发的,用于导航器浏览器。 C 一样,该语言没有自己的输入或者输出构造。 C 依赖标准 I/O 库,JavaScript引擎依赖于它所嵌入的主机环境。 这种脚本语言适用于其他语言可能调用的过程,子程序和函数,它们都在一种结构中: 自定义函数的一个主要用法是与web页面的文档对象模型( DOM ) 交互,以便单独使用 HTML。 JScript是与netscape的JavaScript等同的,用于微软的IE。

在JavaScript中创建自定义对象

创建一个新的JavaScript对象包括两个步骤。 首先,需要创建一个函数,它的NAME 将是新类的NAME。 这个函数通常被称为构造函数。 其次,你必须使用以下命令创建对象的实例 新建 运算符后跟对象 NAME 及其所需的任何参数。 下面的代码定义一个 Person 函数,然后使用 新建 运算符:

function</CODE> Person( name, surname )
{
 this.name = name;
 this.surname = surname;
}var salvo = new Person( 'Salvatore', 'Vetro' );

这个 指向使用的当前对象实例,从而允许你添加和修改对象上的属性。

如何将方法添加到对象中?

在JavaScript中,可以通过调用构造函数函数创建的每个对象都有关联的Prototype属性。 添加新方法的语法为:

customeObject.prototype.newMethodName = function;// Specific casePerson.prototype.Speak = function(){...}

如果将一个方法添加到对象的原型,那么使用对象函数创建的所有对象都将具有新方法。 要注意,prototype 本身就是一个对象,可以通过对象字面语法来指定属性和方法:

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();

每次脚本试图读取或者写入对象的属性时,JavaScript都会按照特定的顺序在 MATCH 中搜索属性 NAME。 序列如下所示:

  • 如果属性具有分配给当前( 本地) 对象的值,则这是使用。
  • 如果没有局部值,则检查对象构造函数的属性Prototype的值。
  • 继续Prototype链,直到找到属性匹配或者搜索到达本机对象。 如果更改构造函数属性的值,并且不重写该构造函数实例中的属性值,JavaScript将返回构造函数属性的当前值。

观察者设计 Pattern 类图

观察者设计 Pattern 在主体对象和任意数量的观察者对象之间定义一个one-to-many依赖,因此当subject对象改变状态时,它的所有观察者对象都被自动地通知和更新。

  • 与会者
    • 主题
      • 了解观察者。任意数量的观察者对象都可以观察到。
      • 提供用于附加和分离观察器对象的接口。
    • 观察器
      • 为对象定义更新接口,这些对象应在对象的更改中得到通知。
    • ConcreteSubject
      • 存储ConcreteObserver对象的兴趣状态。
      • 当状态更改时向它的观察者发送通知。
    • ConcreteObserver
      • 维护对ConcreteSubject对象的引用。
      • 存储与主题保持一致的状态。
      • 实现观察者更新接口,使它的状态与主题保持一致。
  • 协作
    • 当发生变化时,ConcreteSubject通知观察者它的状态与自身的状态不一致。
    • 在了解了具体主题的变化后,ConcreteObserver对象可能会查询该主题以获取信息。 ConcreteObserver使用这里信息来协调它的状态与主题的状态。

观察者设计 Pattern 序列图

以下交互图表说明了主题和两个观察者之间的协作:

启动更改请求的观察者对象推迟更新,直到收到来自主题的通知。 Notify 不总是被主题调用。 它可以由观察者或者其他类型的对象调用。

"" 你 究竟 去 了 哪儿?

现在你知道了观察者设计 Pattern 是什么,以及如何使用JavaScript创建定制对象。 可以在类图中看到,你必须定义两种方法( AttachDetach ) inside。 为此,你需要一个 Collection 来执行附加/分离操作。 是时候编写你的第一个 JavaScript ArrayList 了。 首先,你必须定义 ArrayList 应该能够做什么。

Count添加GetAt清除LastIndexOf插入。

function ArrayList()
{
 this.aList = []; //initialize with an empty array}
ArrayList.prototype.Count = function()
{
 returnthis.aList.length;
}
ArrayList.prototype.Add = function( object )
{
 //Object are placed at the end of the arrayreturnthis.aList.push( object );
}
ArrayList.prototype.GetAt = function( index ) //Index must be a number{
 if( index> -1 && index <this.aList.length )
 returnthis.aList[index];
 elsereturn 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 )
 {
 case0:
 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)
 {
 case0:
 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;
}

好了现在你可以创建观察者类和观察者设计 Pattern的主体类。

观察者设计 Pattern的观察者类

你只需定义方法 Update

function Observer()
{
 this.Update = function()
 {
 return;
 }
}

观察者设计 Pattern的主题类

好的,我们来定义三种主要方法: NotifyAddObserverRemoveObserver

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 ));
}

JavaScript中的继承

使用JavaScript模拟继承有一些方法。 一个非常简单的方法是定义一个简单的方法叫做 继承 可以用于将对象的所有属性和方法复制到另一个对象。

function inherits(base, extension)
{
 for ( var property in base )
 {
 try {
 extension[property] = base[property];
 }
 catch( warning ){}
 }
}

一个简单的实现

现在需要实现客户端,以便将观察者附加到具体主题。 例如你可以创建一个简单的应用程序,它定义一个主复选框,并将一些复选框作为观察者。 具体的使用者会改变自己的状态,它会通知观察者发生了什么。 任何与主体分离的观察者都将彼此独立地管理通知。

/************* 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);

封闭示例

在特定情况下,任何观察者都以相同的方式管理通知。 当具体主体向观察者通知新状态时,任何观察者都会使用观察状态作为新的值来改变自己的状态。

协作

这篇文章可以改进。 如有任何建议请与我联系。