基于Prototype实现对象级别Observer模式

Prototype框架提供了基于JavaScript语言的面向对象风格的AJAX库,使编写动态WEB程序成为可能。基于PrototypeScriptaculous的流行就是一个很好的证明。<o:p></o:p>

<o:p></o:p>Prototype封装了FormElementEvent,并为Form提供了Observer模式以便于进行事件管理和减少依赖。<o:p></o:p>

问题:<o:p></o:p>

<o:p></o:p>Prototype设计了两种Observer,一种基于Timeout,一种基于事件。但无法支持普通对象级别的Observer。例如在调用A对象的X 方法之后触发B对象的Y方法。本文将尝试一种在对象级别实现Observer的方式。<o:p></o:p>

分析: <o:p></o:p>

<o:p></o:p>Observer模式实现在“被观察者”的行为发生变化时,向多个对象(观察者)发生消息(并由该对象完成Update操作)。面向对象语言借助Interface实现Observer模式。如Java中的java.util.Observable相当于Subject(被观察者),而java.util.Observer接口的实现者(观察者)完成Update操作。

上述方式对于降低类之间依赖不错。但是我们必须从特定的类继承或实现特定的接口。Observer消息触发方式导致问题也需要考虑。详见:http://www.microsoft.com/china/MSDN/library/architecture/patterns/esp/DesObserver.mspx?mfr=true<o:p></o:p>

当然,我们可以在JavaScript中按照上述结构实现Observer会导致更多问题,例如如何实现接口编程?即使这个问题很容易解决,无论从理解和使用上这种模式都不太方便、不够直接。<o:p></o:p>

设计:<o:p></o:p>

再次聚焦Observer模式并观察它的核心,会发现如何实现消息触发是关键。一旦ConcreteSubject对象拥有ConcreteObserver的引用,在消息触发时就可以直接调用后者的Update方法。<o:p></o:p>

<o:p></o:p>
代码执行顺序:
<o:p></o:p>

concreteSubject的对象内部:<o:p></o:p>

if(this.stateChanged())<o:p></o:p>

     concreteObservers.update(this,args);<o:p></o:p>

再看我的问题:在调用A对象X方法之后调用B对象的Y方法。<o:p></o:p>

A对象内部:<o:p></o:p>

this.X();<o:p></o:p>

B.Y();<o:p></o:p>

<o:p></o:p>动态语言特性支持在Runtime时刻改变对象(数据和行为)考虑引入对象Observer及方法register。用户期望A对象的X方法调用后触发B对象Y方法时,将A对象、X方法名称和期望的动作(B.Y)传入register方法,然后在该方法中改写X的行为。<o:p></o:p>

       A. _$_X = A.X;<o:p></o:p>

       A.X = {this._$_X(); B.Y();}<o:p></o:p>

<o:p></o:p>
同时增加
unregister方法设法恢复A对象的行为(X方法)。<o:p></o:p>

<o:p> </o:p>
代码:
<o:p>  </o:p> 

 

js 代码
 
  1. var StringBuffer = Class.create();  
  2. StringBuffer.prototype = {    
  3.     emptyString:"",  
  4.     initialize:function(){  
  5.         this.data=[];  
  6.     },  
  7.     clear:function(){  
  8.         this.data.length=0;  
  9.     },  
  10.     append:function(){        
  11.         for(var i=0,len=arguments.length;i
  12.             this.data[this.data.length]=arguments[i];  
  13.         }  
  14.         return this;  
  15.     },  
  16.     toString:function(){  
  17.         return this.data.join(this.emptyString);  
  18.     }     
  19. };  
  20.   
  21. var Observer = Class.create();  
  22. Observer.prototype = {    
  23.     initialize:function(){  
  24.           
  25.     },  
  26.     /** 
  27.      * register the action to the object's method 
  28.      * @param {Object} object 
  29.      * @param {String} method 
  30.      * @param {String} action 
  31.      */  
  32.     register:function(object,method,action){  
  33.         if(!object || !method || !action || method == typeof String || action == typeof String)return;  
  34.   
  35.         //checks whether the method is existed.   
  36.         var f = object[method];  
  37.         if(!f)return;  
  38.           
  39.         //copy, rename the method and replace it as a new method.  
  40.         var _$_f = "_$_"+method;          
  41.         if(!object[_$_f]){  
  42.             object[_$_f] = f;  
  43.             object[method]= this.createFunction(method,action);           
  44.         }  
  45.     },  
  46.     /** 
  47.      * unregister the action from the object's method 
  48.      * @param {Object} object 
  49.      * @param {Object} method 
  50.      */  
  51.     unregister:function(object,method){  
  52.         if(!object||!method)return;  
  53.         var _$_f = "_$_"+method;      
  54.         if(object[_$_f]){  
  55.             object[method] = null;  
  56.             object[method] = object[_$_f];  
  57.             object[_$_f] = null;  
  58.         }     
  59.     },  
  60.     /** 
  61.      * create a new function that invokes both the method and the action  
  62.      * @param {String} method 
  63.      * @param {String} action 
  64.      */  
  65.     createFunction:function(method,action){  
  66.         var sb = new StringBuffer();  
  67.         sb.append("this[\"_$_",method,"\"]();\r",action);         
  68.         return new Function(sb.toString());  
  69.     }     
  70. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值