[Tips]javascript设计模式漫谈之使用委托
文: jno <jno[at]ph4nt0m.org>
http://www.ph4nt0m.org
Text Mode
.net语言中有委托这个概念,委托的本质可以说是面向对象语言中安全的函数指针,javascript语言标准中虽然没有委托概念,但是却可以使用委托。因为在javascript是一个基于对象的语言,函数也是对象,所以自然就可以作为参数传递,于是也就可以使用委托机制。
这里举一个委托在异步调用中例子,来说明委托的用法,例子是对XmlHttp的简单封装:
<script type="text/javascript">
<!--
/*
* XmlHttp 类
*/
var XmlHttp = function() {
var o = null;
var readyStateChange = function(processResponseProc) {
if (o.readyState == 4) {
if (o.status == 200) {
processResponseProc(o.responseText);
} else {
processResponseProc(null);
}
}
};
return {
/*
* init 方法
*
* 返回值
* 如果初始化成功则返回 true,否则返回false
*
* 说明
* 初始化XmlHttp对象,
*/
init : function() {
if (o == null) {
if (window.XMLHttpRequest) {
try {
o = new XMLHttpRequest();
} catch (ex) {
return false;
}
} else if (window.ActiveXObject) {
try {
o = new ActiveXObject("Msxml4.XMLHttp");
} catch (ex) {
try {
o = new ActiveXObject("Msxml2.XMLHttp");
} catch (ex) {
try {
o = new ActiveXObject("Microsoft.XMLHttp");
} catch (ex) {
return false;
}
}
}
}
}
return true;
},
/*
* get 方法
*
* 参数
* url - 要请求的url
* processResponse - 处理返回结果委托
*
* 返回值
* 如果请求发起成功则返回true,否则返回false
*
* 说明
* 发起http请求
*/
get : function(url, processResponse) {
try {
o.open("GET", url, true);
o.onreadystatechange = function() { readyStateChange(processResponse); };
o.send();
return true;
} catch (ex) {
return false;
}
},
/*
* post 方法
*
* 参数
* url - 要请求的url
* data - 发送的数据,注意这里值必须是urlencode过的
* processResponse - 处理返回结果委托
*
* 返回值
* 如果请求发起成功则返回true,否则返回false
*
* 说明
* 发起post请求
*/
post : function(url, data, processResponse) {
processResponseProc = processResponse;
try {
o.open("POST", url, true);
o.onreadystatechange = function() { readyStateChange(processResponse); };
o.setRequestHeader("Content-Length", data.length);
o.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
o.send(data);
return true;
} catch (ex) {
return false;
}
}
};
};
var xmlhttp = new XmlHttp();
if (xmlhttp.init()) {
xmlhttp.get("http://pstgroup.blogspot.com/", function(response) {
if (response != null) {
document.write(response);
}
});
}
//-->
</script>
<!--
/*
* XmlHttp 类
*/
var XmlHttp = function() {
var o = null;
var readyStateChange = function(processResponseProc) {
if (o.readyState == 4) {
if (o.status == 200) {
processResponseProc(o.responseText);
} else {
processResponseProc(null);
}
}
};
return {
/*
* init 方法
*
* 返回值
* 如果初始化成功则返回 true,否则返回false
*
* 说明
* 初始化XmlHttp对象,
*/
init : function() {
if (o == null) {
if (window.XMLHttpRequest) {
try {
o = new XMLHttpRequest();
} catch (ex) {
return false;
}
} else if (window.ActiveXObject) {
try {
o = new ActiveXObject("Msxml4.XMLHttp");
} catch (ex) {
try {
o = new ActiveXObject("Msxml2.XMLHttp");
} catch (ex) {
try {
o = new ActiveXObject("Microsoft.XMLHttp");
} catch (ex) {
return false;
}
}
}
}
}
return true;
},
/*
* get 方法
*
* 参数
* url - 要请求的url
* processResponse - 处理返回结果委托
*
* 返回值
* 如果请求发起成功则返回true,否则返回false
*
* 说明
* 发起http请求
*/
get : function(url, processResponse) {
try {
o.open("GET", url, true);
o.onreadystatechange = function() { readyStateChange(processResponse); };
o.send();
return true;
} catch (ex) {
return false;
}
},
/*
* post 方法
*
* 参数
* url - 要请求的url
* data - 发送的数据,注意这里值必须是urlencode过的
* processResponse - 处理返回结果委托
*
* 返回值
* 如果请求发起成功则返回true,否则返回false
*
* 说明
* 发起post请求
*/
post : function(url, data, processResponse) {
processResponseProc = processResponse;
try {
o.open("POST", url, true);
o.onreadystatechange = function() { readyStateChange(processResponse); };
o.setRequestHeader("Content-Length", data.length);
o.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
o.send(data);
return true;
} catch (ex) {
return false;
}
}
};
};
var xmlhttp = new XmlHttp();
if (xmlhttp.init()) {
xmlhttp.get("http://pstgroup.blogspot.com/", function(response) {
if (response != null) {
document.write(response);
}
});
}
//-->
</script>
这里get和post方法都是异步调用,都需要传入有一个processResponse参数,这个参数是http返回内容处理函数,也就是我们所说的委托概念,对象内部会在http请求返回后回调该函数来处理返回的内容,委托这个词很形象,XmlHttp类并不知道调用者要对返回结果干些什么,于是就委托给这个传递近来的函数来做。
委托可以很好的降低不同功能之间的耦合,这个例子使用委托就符合Open-Close原则,如果有新的处理返回结果的需求可以很容易扩展,不用改动现有代码,比如我们的新需求是alert返回结果:
var xmlhttp = new XmlHttp();
if (xmlhttp.init()) {
xmlhttp.get("http://pstgroup.blogspot.com/", function(response) {
if (response != null) {
alert(response);
}
});
}
if (xmlhttp.init()) {
xmlhttp.get("http://pstgroup.blogspot.com/", function(response) {
if (response != null) {
alert(response);
}
});
}
委托之所以适合异步调用,是因为异步调用符合委托的使用场景:调用者A调用被调用者B,由于调用过程是异步的,不会立刻返回结果,所以B在拿到返回结果时,有需要依赖于A来处理结果。当在类设计时发现类之间双向互相依赖的情况时,可以考虑使用委托。
没有评论:
发表评论