这是一种组织性的模式,它可以用来修改类和对象的接口,使其更便于使用。它可以让程序员过得更轻松,使他们的代码变得更容易管理。
门面模式有两个作用:
var addEvent = function(el, ty, fn){ var cases = [ function(el, ty, fn) { el.addEventListener(ty, fn, false); }, function(el, ty, fn) { el.attachEvent('on'+ty, fn); }, function(el, ty, fn) { el['on'+ty] = fn; } ]; if(el.addEventListener){ $.addEvent = cases[0]; }else if(el.attachEvent){ $.addEvent = cases[1]; }else{ $.addEvent = cases[2]; } $.addEvent(el, ty, fn); },
addEvent函数就是一个基本的门面,有了它,就可以把检查代码封装在一个地方,这可以让代码变得更简洁。这是一个应用门面模式对付一组设计得比较糟糕的API的案例,其具体做法就是用一个精心设计的API来包装她们。
function a(x){ return x; } function b(x){ return y; } function ab(x, y){ a(x); b(y); }
门面模式的另一个好处表现在对函数的组合上。这些组合而得的函数又叫便利函数。
其实我们完全可以将a,b两个函数在一开始的时候就放入到ab函数中,那么门面模式在这里有什么好处呢?
答案是分别提供a、b和ab这几个函数可以获得更多力度控制和灵活性。组合a和b可能会对应用程序造成破坏或者意想不到的结果。
下面就是一个常见的门面模式:
var JChen = window.JChen || {}; JChen.util = { stopPropragation: function(e){ if(e.stopPropragation){ e.stopPropragation(); }else{ e.cancelBubble = true; } }, preventEvent: function(e){ if(e.preventEvent){ e.preventEvent(); }else{ e.returnValue = false; } }, stopEvent: function(e){ //这个就是便利函数 JChen.util.stopPropragation(e); JChen.util.preventEvent(e); } };
设置HTML的样式,只要对样式对象的特定属性赋值即可,例如:
var el = document.getElementById('content'); el.style.color = 'red';
现在假设我们要一次设置几个元素的某个样式。如果分别设置显然是有些笨拙的,这个时候我们就可以使用门面模式了。
function setStyle(el, prop, val){ for(var i= 0, len=el.length; i<len; i++){ document.getElementById(el[i]).style[prop] = val; } } setStyle(['foo', 'bar'], 'color', 'red');
要是我们还可以一次设置多个元素的多个样式就更好了,那样的话就不必反复使用setStyle方法了。
function setCSS(el, styles){ for( var prop in styles){ if(!styles.hasOwnProperty(prop)){ //必须不能是原型上的属性才是应该被设置的样式 continue; } styles(el, prop, styles[prop]); } } setCSS(['foo', 'bar'], { color: 'white', background: 'black', fontSize: '16px' });
现在我们又用了一个门面模式去包含了刚才的门面模式,这下就正点多了。
判断是否应该应用门面模式的关键在于辨认那些反复成组出现的代码。如果函数b经常出现在函数a之后,那么门面模式就派上用场了。
另一个可能的目的是应对Javascript内置函数在不同浏览器中的表现的情况。addEvent就是其中一例。
编写一次组合代码,然后就可以反复使用他,这有助于节省时间和精力。
通过门面模式,可以避免与下层子系统紧密耦合。这样可以对这个系统进行修改而不影响到客户代码。(也就是多粒度的控制)
有时候门面元素也会带来一些不必要的额外负担。方便的东西不一定就得用。门面模式常常会被滥用。在使用你心仪的门面函数之前请三思。