深入理解JavaScript系列(44):设计模式之桥接模式详解
介绍
桥接模式(Bridge)将抽象部分与它的实现部分分离,使它们都可以独立地变化。
正文
桥接模式最常用在事件监控上,先看一段代码:
addEvent(element,'click',getBeerById); functiongetBeerById(e){ varid=this.id; asyncRequest('GET','beer.uri?id='+id,function(resp){ //Callbackresponse. console.log('RequestedBeer:'+resp.responseText); }); }
上述代码,有个问题就是getBeerById必须要有浏览器的上下文才能使用,因为其内部使用了this.id这个属性,如果没用上下文,那就歇菜了。所以说一般稍微有经验的程序员都会将程序改造成如下形式:
functiongetBeerById(id,callback){ //通过ID发送请求,然后返回数据 asyncRequest('GET','beer.uri?id='+id,function(resp){ //callbackresponse callback(resp.responseText); }); }
实用多了,对吧?首先ID可以随意传入,而且还提供了一个callback函数用于自定义处理函数。但是这个和桥接有什么关系呢?这就是下段代码所要体现的了:
addEvent(element,'click',getBeerByIdBridge); functiongetBeerByIdBridge(e){ getBeerById(this.id,function(beer){ console.log('RequestedBeer:'+beer); }); }
这里的getBeerByIdBridge就是我们定义的桥,用于将抽象的click事件和getBeerById连接起来,同时将事件源的ID,以及自定义的call函数(console.log输出)作为参数传入到getBeerById函数里。
这个例子看起来有些简单,我们再来一个复杂点的实战例子。
实战XHR连接队列
我们要构建一个队列,队列里存放了很多ajax请求,使用队列(queue)主要是因为要确保先加入的请求先被处理。任何时候,我们可以暂停请求、删除请求、重试请求以及支持对各个请求的订阅事件。
基础核心函数
在正式开始之前,我们先定义一下核心的几个封装函数,首先第一个是异步请求的函数封装:
varasyncRequest=(function(){ functionhandleReadyState(o,callback){ varpoll=window.setInterval( function(){ if(o&&o.readyState==4){ window.clearInterval(poll); if(callback){ callback(o); } } }, 50 ); }
vargetXHR=function(){ varhttp; try{ http=newXMLHttpRequest; getXHR=function(){ returnnewXMLHttpRequest; }; }
catch(e){ varmsxml=[ 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP' ];
for(vari=0,len=msxml.length;i<len;++i){ try{ http=newActiveXObject(msxml[i]); getXHR=function(){ returnnewActiveXObject(msxml[i]); }; break; } catch(e){} } } returnhttp; };
returnfunction(method,uri,callback,postData){ varhttp=getXHR(); http.open(method,uri,true); handleReadyState(http,callback); http.send(postData||null); returnhttp; }; })();