外观模式(Facade)为子系统中的一组接口提供了一个一致的界面,此模块定义了一个高层接口,这个接口值得这一子系统更加容易使用。
外观模式在JS中常常用于解决浏览器兼容性问题。
外观模式不仅简化类中的接口,而且对接口与调用者也进行了解耦。外观模式经常被认为开发者必备,它可以将一些复杂操作封装起来,并创建一个简单的接口用于调用。
外观模式经常被用于JavaScript类库里,通过它封装一些接口用于兼容多浏览器,外观模式可以让我们间接调用子系统,从而避免因直接访问子系统而产生不必要的错误。
外观模式的优势是易于使用,而且本身也比较轻量级。但也有缺点 外观模式被开发者连续使用时会产生一定的性能问题,因为在每次调用时都要检测功能的可用性。
下面是一段未优化过的代码,我们使用了外观模式通过检测浏览器特性的方式来创建一个跨浏览器的使用方法。
比如对document
对象添加click
事件的时候:
function addEvent(dom, type, fn) {
if (dom.addEventListener) { // 支持DOM2级事件处理方法的浏览器
dom.addEventListener(type, fn, false)
} else if (dom.attachEvent) { // 不支持DOM2级但支持attachEvent
dom.attachEvent('on' + type, fn)
} else {
dom['on' + type] = fn // 都不支持的浏览器
}
}
const myInput = document.getElementById('myinput')
addEvent(myInput, 'click', function() {console.log('绑定 click 事件')})
还可以用来解决一些其他的浏览器兼容性问题:
const getEvent = function(event) { // 获取事件对象
return event || window.event // IE下window.event
}
const getTarget = function(event) { // 获取事件元素
const event = getEvent(event)
return event.target || event.srcElement // IE下event.srcElement
}
const preventDefault = function(event) { // 阻止默认事件
const event = getEvent(event)
if (event.preventDefault) {event.preventDefault()}
else {event.returnValue = false} // IE下
}
const cancelBubble = function(event) {
const event = getEvent(event)
if (event.stopPropagation) {event.stopPropagation()}
else {event.cancelBubble = true} // IE下
}
document.onclick = function(e) {
preventDefault(e)
if (getTarget(e) !== document.getElementById('myinput')) {console.log('呵呵')}
}
那么何时使用外观模式呢?一般来说分三个阶段:
Facade
也是非常合适的,为系统开发一个外观Facade
类,为设计粗糙和高度复杂的遗留代码提供比较清晰的接口,让新系统和Facade
对象交互,Facade
与遗留代码交互所有的复杂工作。本文是系列文章,可以相互参考印证,共同进步~
网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出~
参考: