JavaScript 外觀模式

2018-08-02 16:25 更新

外觀模式

當(dāng)我們提出一個(gè)門(mén)面,我們要向這個(gè)世界展現(xiàn)的是一個(gè)外觀,這一外觀可能藏匿著一種非常與眾不同的真實(shí)。這就是我們即將要回顧的模式背后的靈感——門(mén)面模式。這一模式提供了面向一種更大型的代碼體提供了一個(gè)的更高級(jí)別的舒適的接口,隱藏了其真正的潛在復(fù)雜性。把這一模式想象成要是呈現(xiàn)給開(kāi)發(fā)者簡(jiǎn)化的API,一些總是會(huì)提升使用性能的東西。

門(mén)面是一種經(jīng)常可以在Javascript庫(kù)中看到的結(jié)構(gòu)性模式,像在jQuery中,盡管一種實(shí)現(xiàn)可能支持帶有廣泛行為的方法,但僅僅只有這些方法的“門(mén)面”或者說(shuō)被限制住的抽象才會(huì)公開(kāi)展現(xiàn)出來(lái)供人們所使用。

這允許我們直接同門(mén)面,而不是同幕后的子系統(tǒng)交互。不論何時(shí)我們使用jQuery的$(el).css或者$(el).animate()方法,我們實(shí)際上都是在使用一個(gè)門(mén)面——更加簡(jiǎn)單的公共接口讓我們避免為了使得行為工作起來(lái)而不得不去手動(dòng)調(diào)用jQuery核心的內(nèi)置方法。這也避免了手動(dòng)同DOM API交互和維護(hù)狀態(tài)變量的需要。

應(yīng)該考慮對(duì)jQuery的核心方法做一層中間抽象。對(duì)于開(kāi)發(fā)者來(lái)說(shuō)更直接的負(fù)擔(dān)是DOM API,而門(mén)面使得jQuery使用起來(lái)如此的容易。

為了在我們所學(xué)的基礎(chǔ)上進(jìn)行構(gòu)建,門(mén)面模式同時(shí)需要簡(jiǎn)化一個(gè)類(lèi)的接口,和把類(lèi)同使用它的代碼解耦。這給予了我們使用一種方式直接同子系統(tǒng)交互的能力,這一方式有時(shí)候會(huì)比直接訪問(wèn)子系統(tǒng)更加不容易出錯(cuò)。門(mén)面的優(yōu)勢(shì)包括易用,還有常常實(shí)現(xiàn)起這個(gè)模式來(lái)只是一小段路,不費(fèi)力。

讓我們通過(guò)實(shí)踐來(lái)看看這個(gè)模式。這是一個(gè)沒(méi)有經(jīng)過(guò)優(yōu)化的代碼示例,但是這里我們使用了一個(gè)門(mén)面來(lái)簡(jiǎn)化跨瀏覽器事件監(jiān)聽(tīng)的接口。我們創(chuàng)建了一個(gè)公共的方法來(lái)實(shí)現(xiàn),此方法 能夠被用在檢查特性的存在的代碼中,以便這段代碼能夠提供一種安全和跨瀏覽器兼容方案。

var addMyEvent = function( el,ev,fn ){

   if( el.addEventListener ){
            el.addEventListener( ev,fn, false );
      }else if(el.attachEvent){
            el.attachEvent( "on" + ev, fn );
      } else{
           el["on" + ev] = fn;
    }

};

我們都熟知jQuery的$(document).ready(..),使 用了一種類(lèi)似的方式。在內(nèi)部,這實(shí)際上是考一個(gè)叫做bindReady()的方法來(lái)驅(qū)動(dòng)的,它做了一些這樣的事:

bindReady: function() {
    ...
    if ( document.addEventListener ) {
      // Use the handy event callback
      document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

      // A fallback to window.onload, that will always work
      window.addEventListener( "load", jQuery.ready, false );

    // If IE event model is used
    } else if ( document.attachEvent ) {

      document.attachEvent( "onreadystatechange", DOMContentLoaded );

      // A fallback to window.onload, that will always work
      window.attachEvent( "onload", jQuery.ready );

這是門(mén)面的另外一個(gè)例子,其它人只需要使用被$(document).ready(...)有限暴露的簡(jiǎn)單接口,而更加復(fù)雜的實(shí)現(xiàn)被從視野中隱藏了。

門(mén)面不僅僅只被用在它們自己身上,它們也能夠被用來(lái)同其它的模式諸如模塊模式進(jìn)行集成。如我們?cè)谙旅嫠吹降模覀兡K模式的實(shí)體包含許多被定義為私有的方法。門(mén)面則被用來(lái)提供訪問(wèn)這些方法的更加簡(jiǎn)單的API:

var module = (function() {

    var _private = {
        i:5,
        get : function() {
            console.log( "current value:" + this.i);
        },
        set : function( val ) {
            this.i = val;
        },
        run : function() {
            console.log( "running" );
        },
        jump: function(){
            console.log( "jumping" );
        }
    };

    return {

        facade : function( args ) {
            _private.set(args.val);
            _private.get();
            if ( args.run ) {
                _private.run();
            }
        }
    };
}());

// Outputs: "current value: 10" and "running"
module.facade( {run: true, val:10} );

在這個(gè)示例中,調(diào)用module.facade()將會(huì)觸發(fā)一堆模塊中的私有方法。但再一次,用戶(hù)并不需要關(guān)心這些。我們已經(jīng)使得對(duì)用戶(hù)而言不需要擔(dān)心實(shí)現(xiàn)級(jí)別的細(xì)節(jié)就能消受一種特性。

關(guān)于抽象的注意事項(xiàng)

門(mén)面一般沒(méi)有多少缺陷,但是性能是值得注意的問(wèn)題。也就是說(shuō),需要確定門(mén)面在為我們提供實(shí)現(xiàn)的同時(shí)是否為我們帶來(lái)了隱性的消耗,如果是這樣的話,那么這種消耗是否合理?;氐絡(luò)Query庫(kù),我們都知道getElementById('identifier')和$("#identifier")都能夠被用來(lái)借助ID查找頁(yè)面上的一個(gè)元素。

然而你是否知道getElementById()擁有更高數(shù)量級(jí)的速度呢?來(lái)瞧瞧這個(gè)jsPerf的測(cè)試,看一看在每一個(gè)瀏覽器級(jí)別的結(jié)果:http://jsperf.com/getelementbyid-vs-jquery-id。當(dāng)然現(xiàn)在,我們應(yīng)該牢記在心的是jQuery(和Sizzle-它的的選擇器引擎)在幕后對(duì)我們的查詢(xún)(而這返回的是一個(gè)jQuery對(duì)象,并不是一個(gè)DOM節(jié)點(diǎn))做了更大量的優(yōu)化。

這個(gè)特定的門(mén)面模式所面臨的挑戰(zhàn)就是,為了提供一種優(yōu)雅的接受和轉(zhuǎn)換多種查詢(xún)類(lèi)型的選擇器功能,就會(huì)有在抽象上的隱性成本。用戶(hù)并不需要訪問(wèn)jQuery.getById("identifier")或者jQuery.getbyClass("identifier")等等方法。那就是說(shuō),在性能上權(quán)衡已經(jīng)通過(guò)了多年的實(shí)踐考量,并且?guī)Я薺Query的成功,一個(gè)實(shí)際上為團(tuán)隊(duì)工作得很好的門(mén)面。

當(dāng)使用這個(gè)模式的時(shí)候,嘗試了解任何有關(guān)性能上面的消耗,要知道它們是否值得以抽象的級(jí)別被提供出來(lái)調(diào)用。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)