js设计模式-桥接模式
桥接模式定义:桥梁模式的用意是"将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化"。这句话有三个关键词,也就是抽象化、实现化和脱耦。
最简单的桥接模式例子:事件监听器
addEvent(element,"click",getResultByIdBridge); function getResultByIdBridge(e){ getById(this.id, function(result){ //TODO: this is operate result }); }
桥接模式复杂例子:构建XHR连接队列
1 var asyncRequest = (function(){ 2 3 function handleReadyState(o,callback){ 4 var poll = window.setInterval(function(){ 5 if(o && o.readyState ==4){ 6 window.clearInterval(poll); 7 if(callback) callback(o); 8 } 9 },50); 10 } 11 12 var getXHR = function(){ 13 var http; 14 try{ 15 http = new XMLHttpRequest(); 16 getXHR = function(){ 17 return new XMLHttpRequest(); 18 }; 19 }catch(e){ 20 var msxml = ["MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"]; 21 for(var i =0, len = msxml.length;i <len;i++){ 22 try{ 23 http = new ActiveXObject(msxml[i]); 24 getXHR = function(){ 25 return new ActiveXObject(msxml[i]); 26 }; 27 break; 28 }catch(e){} 29 } 30 } 31 return http; 32 } 33 34 return function(method,url,callback,postData){ 35 var http = getXHR(); 36 console.log("send url is:" + url); 37 http.open(method,url,true); 38 handleReadyState(http,callback); 39 http.send(postData || null); 40 } 41 })(); 42 43 Function.prototype.method = function(name,fn){ 44 this.prototype[name] = fn; 45 return this; 46 } 47 48 if(!Array.prototype.forEach){ 49 Array.method("forEach",function(fn,thisObj){ 50 var scope = thisObj || window; 51 for(var i = 0, len = this.length;i<len;i++){ 52 fn.call(scope,this[i],i,this); 53 } 54 }) 55 } 56 57 if(!Array.prototype.filter){ 58 Array.method("filter",function(fn,thisObj){ 59 var scope = thisObj || window; 60 var a = []; 61 for(var i = 0 , len = this.length;i<len;i++){ 62 if(fn.call(scope,this[i],i,this)){ 63 a.push(this[i]); 64 } 65 } 66 return a; 67 }) 68 } 69 70 71 /******************************************/ 72 window.DED = window.DED || {}; 73 DED.util = DED.util || {}; 74 DED.util.Observer = function(){ 75 this.fns = []; 76 } 77 DED.util.Observer.prototype = { 78 subscribe:function(fn){ //签署 79 this.fns.push(fn); 80 }, 81 unsubscribe:function(fn){ 82 this.fns = this.fns.filter(function(item){ 83 if(item != fn){ 84 return item; 85 } 86 }); 87 }, 88 fire:function(o){ 89 this.fns.forEach(function(item){ 90 item(o); 91 }); 92 } 93 } 94 95 DED.Queue = function(){ 96 this.queue = []; 97 this.onComplete = new DED.util.Observer(); 98 this.onFailure = new DED.util.Observer(); 99 this.onFlush = new DED.util.Observer(); 100 101 this.retryCount = 3; 102 this.currentRetry = 0; 103 this.paused = false; 104 this.timeout = 5000; 105 this.conn = {}; 106 this.timer = {}; 107 }; 108 109 DED.Queue.method("flush",function(){ 110 if(!this.queue.length >0){ 111 return ; 112 } 113 if(this.paused){ 114 this.paused = false; 115 return; 116 } 117 118 var that = this; 119 this.currentRetry++; 120 var abort = function(){ 121 that.conn.abort(); 122 if(that.currentRetry == that.retryCount){ 123 that.onFailure.fire(); 124 that.currentRetry = 0; 125 }else{ 126 that.flush(); 127 } 128 }; 129 130 this.timer = window.setTimeout(abort,this.timeout); 131 var callback = function(o){ 132 window.clearTimeout(that.timer); 133 that.currentRetry = 0; 134 that.queue.shift(); 135 that.onFlush.fire(o.responseText); 136 if(that.queue.length == 0){ 137 that.onComplete.fire(); 138 return; 139 } 140 that.flush(); 141 }; 142 143 this.conn = asyncRequest(this.queue[0]["method"],this.queue[0]["url"],callback,this.queue[0]["params"]); 144 }). 145 method("setRetryCount",function(count){ 146 this.retryCount = count; 147 }). 148 method("setTimeout",function(time){ 149 this.timeout = time; 150 }). 151 method("add",function(o){ 152 this.queue.push(o); 153 }). 154 method("pause",function(){ 155 this.paused = true; 156 }). 157 method("dequeue",function(){ 158 this.queue.pop(); 159 }). 160 method("clear",function(){ 161 this.queue = []; 162 });
对应的html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 <style type="text/css"> 7 body{font:100% georgia,times,serif} 8 h1,h2{font-weight: normal;} 9 #queue-items{height:1.5rem;} 10 #add-stuff{padding:0.5rem; background:#ddd; border:1px solid #bbb;} 11 #result-area{padding:0.5rem; border: 1px solid #bbb;} 12 </style> 13 </head> 14 <body id="exmapl"> 15 <div id="doc"> 16 <h1>Ajax Conection Queue</h1> 17 <div id="queue-items"></div> 18 <div id="add-stuff"> 19 <h2>Add Requests to Queue</h2> 20 <ul id="adders"> 21 <li><a href="#" id="action-01">add 01 to Queue</a></li> 22 <li><a href="#" id="action-02">add 02 to Queue</a></li> 23 <li><a href="#" id="action-03">add 03 to Queue</a></li> 24 <li><a href="#" id="action-04">add 04 to Queue</a></li> 25 </ul> 26 </div> 27 <h2>oTther Queue actions</h2> 28 <ul id="items"> 29 <li><a href="#" id="flush">Flush</a></li> 30 <li><a href="#" id="dequeue">dequeue</a></li> 31 <li><a href="#" id="pause">pause</a></li> 32 <li><a href="#" id="clear">clear</a></li> 33 </ul> 34 35 <div id="result-area"> 36 <h2>Results:</h2> 37 <div id="results"></div> 38 </div> 39 </div> 40 </body> 41 </html> 42 <script type="text/javascript" src="Bridge.js"></script> 43 <script> 44 window.onload = function(){ 45 var q = new DED.Queue(); 46 q.setRetryCount(5); 47 q.setTimeout(3000); 48 49 50 var items = document.getElementById("items"); 51 var queue = document.getElementById("queue-items"); 52 var requests = []; 53 q.onFlush.subscribe(function(data){ 54 results.innerHTML = data; 55 requests.shift(); 56 queue.innerHTML = requests.toString(); 57 }); 58 q.onFailure.subscribe(function(){ 59 results.innerHTML += "<span style='color:red;'>Connection error</span>"; 60 }); 61 62 q.onComplete.subscribe(function(){ 63 results.innerHTML += "<span style='color:green;'>Completed!</span>"; 64 }); 65 66 var actionDispatcher = function(element){ 67 switch(element){ 68 case "flush": 69 q.flush(); 70 break; 71 case "dequeue": 72 requests.pop(); 73 queue.innerHTML = requests.toString(); 74 break; 75 case "pause": 76 q.pause(); 77 break; 78 case "clear": 79 q.clear(); 80 requests = []; 81 queue.innerHTML = ""; 82 break; 83 } 84 }; 85 86 var addRequest = function(request){ 87 var data = request.split("-")[1]; 88 q.add({ 89 method:"GET", 90 url:"http://127.0.0.1:8020/WS_WEB/JS%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/js/ajax.json?data=" + data, 91 params:null 92 }); 93 requests.push(data); 94 queue.innerHTML = requests.toString(); 95 }; 96 97 items.onclick = function(e){ 98 var e = e || window.event; 99 var src = e.target || e.srcElement; 100 try{ 101 e.preventDefault(); 102 }catch(e){ 103 e.returnValue = false; 104 } 105 if(src.id){ 106 actionDispatcher(src.id); 107 } 108 }; 109 110 var adders = document.getElementById("adders"); 111 adders.onclick = function(){ 112 var e = e || window.event; 113 var src = e.target || e.srcElement; 114 if(e.preventDefault){ 115 e.preventDefault(); 116 }else{ 117 e.returnValue = false; 118 } 119 if(src.id)addRequest(src.id); 120 } 121 122 } 123 124 </script>