以jq為案例看套餐服務---外觀模式
套餐服務--外觀模式,屬於大類結構型設計模式的一種,通常是為一組複雜的子系統介面提供一個更高階的統一介面,通過這個介面讓使用者對子系統的介面更加容易訪問。
在js中有時也會對底層結構相容性做統一的封裝來簡化使用者的使用。
備註:本文的案例以es5為主,部分會涉及jq的程式碼,大家理解思想就好。如果你有es6以及目前三大框架的例項應用案例,歡迎分享。
生活場景延伸
相信大家都經常下飯館或者點外賣,一般情況下每個店面都會有自己的推薦套餐,這個套餐裡配置了菜、湯、米飯等,在點了套餐時就不需要關注這個套餐下每個類的名字叫什麼。
飯店的這種將幾個不同品種的需求搭配在一起捆綁給顧客的方式就是套餐模式,和我們的外觀模式是有共通之處的。
從點選事件說起----相容方式&&底層向上封裝
相信古老的程式員都用過jq,還有jq的click事件,一般的寫法是這樣的對吧。
$(target).on(eventType,fn) 複製程式碼
也相信大家都用過或者多少知道一點js的原生語法,繫結事件是如何寫的。
let dom= document.querySelector(target) dom.addEventListener(type,fn,false) 複製程式碼
發生jq的寫法很親民,很簡潔有沒有,把使用變的更加簡潔了,另外一家是大家可能不知道的,其實addEventListener 並不是一個相容的寫法,其應該的相容寫法是這樣的:
if(dom.addEventListener){ dom.addEventListener(type,fn,false) } else if(dom.attachEvent) { dom.attachEvent('on'+type,fn) } else { dom['on'+type] = fn } 複製程式碼
是這樣的麼?我們找到jq的事件原始碼看一下吧 :原始碼檔案位置(要到比較老的1.x的版本才會找到這部分針對事件寫的相容程式碼哦):ofollow,noindex">github.com/jquery/jque…
// event.add 方法中,183行開始 // Init the event handler queue if we're the first if ( !( handlers = events[ type ] ) ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener/attachEvent if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element //use different ways to add event according to different support situation (Robin 批註) if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } } } 複製程式碼
結論:從上面可以看出一個簡單的新增事件就用了外觀模式,而實際上add事件本身在jq看來也是屬於封裝的底層,其通過再一次封裝,將其封裝到了on方法中。在整個jq的框架中,在相容寫法上、向上封裝上不斷地運用了外觀模式來設計。
function on( elem, types, selector, data, fn, one ) { //省略若干程式碼 return elem.each( function() { jQuery.event.add( this, types, fn, data, selector ); } ); } 複製程式碼
小型程式碼庫
還是以剛才的jq庫為例子,在完成on方法定義的時候,我們看到了一系列的套餐服務的設計暴露出來。每一個看似簡單的服務或者套餐或者語法都是一個外觀模式的最佳實踐。
jQuery.fn.extend( { on: function( types, selector, data, fn ) { return on( this, types, selector, data, fn ); }, one: function( types, selector, data, fn ) { return on( this, types, selector, data, fn, 1 ); }, ... }) 複製程式碼