基於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. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章