1、简介:
桥接模式的作用在于“将抽线与实现分离开来,以便二者独立变化”。例如我们经常使用的各种跨操作系统的浏览器,比如FF,在Windows系统下,你可以用FF浏览器,在Linux下也可以使用FF,而两者的表现基本是没有差异的,提供的JS之类的接口也是相同的,然而再往底层,FF需要调用操作系统的一些API进行实现某个功能,在Windows和Linux下,二者是有很大区别的,而在底层的Windows和Linux的两个实现,FF将其隐藏起来,最终提供给我们一个统一的编程接口,这便是一个桥接,使得我们无需去了解操作系统的差异(了解浏览器的差异就已经够呛了= =!)。 当然在JS中,这种差异巨大的实现已经不存在了,对于浏览器间的差异一般只需要利用外观(Facade)模式(以后会写到)提供简洁的接口就可以克服。在设计一个Javascirpt API的时候,桥接模式有助于弱化它与使用它的类和对象之间的耦合。
2、示例
桥接模式最常见和实际的应用场合之一是事件监听回调函数,以下面的淘宝笔试题(我稍微改动了下)为例:
<ul id="score">
<li>小王<em>70</em></li>
<li>小李<em>68</em></li>
<li>小张<em>80</em></li>
<li>小四<em>50</em></li>
<li>小五<em>40</em></li>
<li>小六<em>30</em></li>
</ul>
<input type="button" value="sort" id="sort" />
要求:点击sort按钮,可以将列表内的内容按分数从小到大排序。分析下结构,分值都包含在em标签内,于是获取score下的em标签,再对比他们的文本节点值就可以对其进行排序,也许很自然的一个解法如下所示:
window.onload = function(){
/*比较函数*/
var scoreCompare = function(elem1, elem2){
return parseInt(elem1.firstChild.nodeValue) - parseInt(elem2.firstChild.nodeValue);
};
/*事件响应函数*/
document.getElementById('sort').onclick = function(){
var list = document.getElementById('score'),
ems = list.getElementsByTagName('em'),
elems = [];
/*获得em元素数组*/
try {
elems = Array.prototype.slice.call(ems, 0);
}
catch (e) {/*IE不支持数组方法对元素集合对象调用*/
for (var i = 0, len = ems.length; i < len; ++i) {
elems.push(ems[i]);
}
}
/*对em元素数组排序*/
elems.sort(scoreCompare);
/*按顺序连接到ul节点之后,这里注意下appendChild的妙处,若节点已经存在于文档上,
*则appendChild会将节点从原来的位置删除,接在新的位置上,而不用把原来节点复制,移除,再添加*/
for (var i = 0, len = elems.length; i < len; ++i) {
list.appendChild(elems[i].parentNode);
}
};
};
从上面的JS代码来看,确实达到了效果,不过某天客户有了新需求了,em标签换了,用strong来包含了,又或者某天要对表格排序,难道还要再去写这么一大堆的代码吗?现在我们的任务就是要从上面的代码中抽取出可重用的部分。
能重用的地方就是将标签集合元素转化为数组,以便我们进行排序,可以想象将元素集合对象转化为数组的地方肯定会很多。于是提取出来的函数如下:
function NodeListToArray(list){
var elems = [];
try {
elems = Array.prototype.slice.call(list, 0);
}
catch (e) {/*For IE*/
for (var i = 0, len = list.length; i < len; ++i) {
elems.push(list[i]);
}
}
return elems;
}
上面的函数将NodeList元素集合对象转化为数组返回后,根据排序函数的需要进行排序,事件监听函数再根据HTML结构添加排序后的节点。这里NodeListToArray就是一个Birdge,将NodeList桥接为数组,从而能利用数组的内置方法,如排序等,如果哪天需要从大到小排序,也同样可以利用数组的reverse方法,若单纯的对NodeList排序,怕是光写个排序函数都够呛,且效率肯定没内置函数来得快。即使某天结构变了,可能要对表格排序,流程也是一致的,获得需要排序的集合,转化为数组,调用数组的内置方法,接着根据HTML结构重接节点。
3、其他
桥接模式还可以用于连接公开的API代码和私有的实现代码,外部通过接口获得私有的信息,最常见就是getter和setter。此外,它还可以用来把多个类连接在一起,提供一组复用的方法,而这些方法则依赖内部的各种类,这意味着把接口作为公开的代码编写,而把类的实现作为私有代码编写。