JS设计模式——7.工厂模式(示例-XHR)
XHR工厂
基本实现
var AjaxHandler = new Interface('AjaxHandler', ['request', 'createXHR']); var SimpleHandler = function(){}; SimpleHandler.prototype = { request: function(method, url, callback, postVars){ var xhr = this.createXHR(); xhr.onreadystatechange = function(){ if(xhr.readyState!==4) return; (xhr.status===200)? callback.success(xhr.responseText, xhr.responseXML): callback.failure(xhr.status); }; xhr.open(method, url, true); if(method !== 'POST') postVars = null; xhr.send(postVars); }, createXHR: function(){ var methods = [ function() {return new XMLHttpRequest();}, function() {return new ActiveXObject('Msxml2.XMLHTTP');}, function() {return new ActiveXObject('Microsoft.XMLHTTP');} ]; for(var i = 0, len=methods.length; i<len; i++){ try{ methods[i](); }catch (e){ continue; } this.createXHR = methods[i]; //memoize the method. return methods[i]; } } };
createXHR这个工厂方法根据当前的宿主环境返回适当的xhr对象.重点是createXHR在首次执行之后就被替换为了methods[i],这个就是memoizing技术了(可以称称之为记录).这样当我们下次用到createXHR的时候就不用在去能力检测了.大大的提升了性能.
SimpleHandler的调用如下:
var myHandler = new SimpleHandler(); var callback = { success: function(responseText){ console.log('Success' + responseText); }, failure: function(statusCode){ console.log('Failure' + statusCode); } }; myHandler.request('GET', 'stript.php', callback);
专用型连接对象
我们对上面的对象进行一个扩展,以便根据网络条件创建专门的请求对象.
首先我们先来创建两个新的处理器类:
1:QueHandler会在发起新的请求之前先确保所有请求都已经成功处理.
var QueHandler = function(){ this.queue = []; this.requestInProgress = false; this.retryDelay = 5; }; extend(QueHandler, SimpleHandler); QueHandler.prototype.request = function(method, url, callback, postVars, override){ if(this.requestInProgress && !override){ this.queue.push({ method: method, url: url, callback: callback, postVars: postVars }); }else{ this.requestInProgress = true; var xhr = this.createXHR(); var that = this; xhr.onreadystatechange = function(){ if(xhr.readyState !== 4) return; if(xhr.status === 200){ callback.success(xhr.responseText, xhr.responseXML); that.advanceQueue(); }else{ callback.failure(xhr.status){ setTimeout(function(){that.request(method, url, callback, postVars, true);}, that.retryDelay*1000); } } }; xhr.open(method, url, true); if(method!=='POST') postVars = null; xhr.send(postVars); } }; QueHandler.prototype.advanceQueue = function(){ if(this.queue.length === 0){ this.requestInProgress = false; return; } var req = this.queue.shift(); this.request(req.method, req.url, req.callback, req.postVars, true); };
2:OffHandler会在用户处于离线状态时把请求缓存起来.
var OffHandler = function(){ this.storedRequests = []; }; extend(OffHandler, SimpleHandler); OffHandler.prototype.request = function(method, url, callback, postVars){ if(XhrManager.isOffline()){ this.storedRequests.push({ method:method, url:url, callback:callback, postVars:postVars }); }else{ this.flushStoredRequests(); OffHandler.superclass.request(method, url, callback, postVars); } }; OffHandler.prototype.flushStoredRequests = function(){ for(var i= 0, len=this.storedRequests.length; i<len; i++){ var req = this.storedRequests[i]; OffHandler.superclass.request(req.method, req.url, req.callback, req.postVars); } }
在运行时选择连接对象
现在该用到工厂模式了.因为程序元根本不知道各个最终用户面临的网络条件,所以要用一个工厂在运行是选择最合适的类.
var XhrManager = { createXhrHandler: function(){ var xhr; if(this.isOffline()){ xhr = new OffHandler(); }else if(this.isHighLatency()){ xhr = new QueHandler(); }else{ xhr = new SimpleHandler(); } Interface.ensureImplements(xhr, AjaxHandler); return xhr; }, isOffline: function(){ //do a quick request with SimpleHandler and see if it success. ... }, isHighLatency: function(){ //do a series of requests with SimpleHandler and time the requests,Best done once, as a branching function. ... } }; var myHandler = XhrManager.createXhrHandler(); var callback = {}; myHandler.request('GET', 'sript.php', callback);
我只想说他的isOffline的实现亮了.