这里拿给DOM元素设置样式的case来演绎在js中怎么使用Facade Pattern。

 

   先看菜鸟的做法:

var element1 = document.getElementById('foo');
element1.style.color = 'red';
var element2 = document.getElementById('bar');
element2.style.color = 'red';
var element3 = document.getElementById('baz');
element3.style.color = 'red';

为了给3个元素增加红色,重复做了3次。

 

     为了不重复造车轮,做一下抽象总结,简化如下: 

function setStyle(elements, prop, val) {
    for (var i = 0, len = elements.length - 1; i < len; ++i) {
        document.getElementById(elements[i]).style[prop] = val;
    }
}
setStyle(['foo', 'bar', 'baz'], 'color', 'red');

再看现在的调用方式,仅一行setStyle即可。再多的元素,只要需要设置的样式key/value相同,一行代码全部搞定。

 

      但是,这还不够。现实情况是,程序可能需要一次性给一个或多个元素设置多个样式属性。基于css的表现形式,继续改进如下:

function setCSS(el, styles) {
    for (var prop in styles) {
        if (!styles.hasOwnProperty(prop)) continue;
        setStyle(el, prop, styles[prop]);
    }
}
setCSS(['foo', 'bar', 'baz'], {
    position: 'absolute',
    top: '50px',
    left: '300px'
});

看看setCSS那一行,后边的属性键值对们是不是很css? 如此好的一个Facade应用,以后可以只对外公开setCSS方法了。 

 

    下面是为了解决霸道的IE和基于DOM标准的浏览器的差别,利用Facade来解决一致性的问题的示例: 

DED.util.Event = {
    getEvent: function (e) {
        return e || window.event;
    },
    getTarget: function (e) {
        return e.target || e.srcElement;
    },
    stopPropagation: function (e) {
        if (e.stopPropagation) {
            e.stopPropagation();
        }
        else {
            e.cancelBubble = true;
        }
    },
    preventDefault: function (e) {
        if (e.preventDefault) {
            e.preventDefault();
        }
        else {
            e.returnValue = false;
        }
    },
    stopEvent: function (e) {
        this.stopPropagation(e);
        this.preventDefault(e);
    }
};

/* test */
addEvent($('example'), 'click', function (e) {
    // Who clicked me.
    console.log(DED.util.Event.getTarget(e));
    // Stop propagating and prevent the default action.
    DED.util.Event.stopEvent(e);
});

 

    至此,可以看出Facade Pattern的主要作用不外2点:1)外外围程序提供比较简洁、人性化的接口;2)内部封装解决一些差异性,是外部看来是一致的。 源码download