# 觀察者模式
另一個我們之前提到過的模式就是觀察者(發布/訂閱)模式.這種模式下,系統中的對象可以在關注的事件發生的時候給其他對象發送消息,也可以被其他對象所通知。
jQuery核心庫很多年前就已經提供了對于類似于發布/訂閱系統的支持,它們稱之為定制事件。
jQuery的早期版本中,可以通過使用jQuery.bind()(訂閱),jQuery.trigger()(發布),和jQuery.unbind()(取消訂閱)來使用這些定制事件,但在近期的版本中,這些都可以通過使用jQuery.on(),jQuery.trigger()和jQuery.off()來完成。
下面我們來看一下實際應用中的一個例子:
~~~
// Equivalent to subscribe(topicName, callback)
$( document ).on( "topicName" , function () {
//..perform some behaviour
});
// Equivalent to publish(topicName)
$( document ).trigger( "topicName" );
// Equivalent to unsubscribe(topicName)
$( document ).off( "topicName" );
~~~
對于jQuery.on()和jQuery.off()的調用最后會經過jQuery的事件系統,與Ajax一樣,由于它們的實現代碼相對較長,我們只看一下實際上事件處理器是在哪兒以及如何將定制事件加入到系統中的:
~~~
jQuery.event = {
add: function( elem, types, handler, data, selector ) {
var elemData, eventHandle, events,
t, tns, type, namespaces, handleObj,
handleObjIn, quick, handlers, special;
...
// Init the element's event structure and main handler,
//if this is the first
events = elemData.events;
if ( !events ) {
elemData.events = events = {};
}
...
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
types = jQuery.trim( hoverHack(types) ).split( " " );
for ( t = 0; t < types.length; t++ ) {
...
// Init the event handler queue if we're the first
handlers = events[ type ];
if ( !handlers ) {
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
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}
}
}
~~~
對于那些喜歡使用傳統的命名方案的人, Ben Alamn對于上面的方法提供了一個簡單的包裝,然后為我們提供了jQuery.publish(),jQuery.subscribe和jQuery.unscribe方法。我之前在書中提到過,現在我們可以完整的看一下這個包裝器。
~~~
(function( $ ) {
var o = $({});
$.subscribe = function() {
o.on.apply(o, arguments);
};
$.unsubscribe = function() {
o.off.apply(o, arguments);
};
$.publish = function() {
o.trigger.apply(o, arguments);
};
}( jQuery ));
~~~
在近期的jQuery版本中,一個多目的的回調對象(jQuery.Callbacks)被提供用來讓用戶在回調列表的基礎上寫新的方案。另一個發布/訂閱系統就是一個使用這個特性寫的方案,它的實現方式如下:
~~~
var topics = {};
jQuery.Topic = function( id ) {
var callbacks,
topic = id && topics[ id ];
if ( !topic ) {
callbacks = jQuery.Callbacks();
topic = {
publish: callbacks.fire,
subscribe: callbacks.add,
unsubscribe: callbacks.remove
};
if ( id ) {
topics[ id ] = topic;
}
}
return topic;
};
~~~
然后可以像下面一樣使用:
~~~
// Subscribers
$.Topic( "mailArrived" ).subscribe( fn1 );
$.Topic( "mailArrived" ).subscribe( fn2 );
$.Topic( "mailSent" ).subscribe( fn1 );
// Publisher
$.Topic( "mailArrived" ).publish( "hello world!" );
$.Topic( "mailSent" ).publish( "woo! mail!" );
// Here, "hello world!" gets pushed to fn1 and fn2
// when the "mailArrived" notification is published
// with "woo! mail!" also being pushed to fn1 when
// the "mailSent" notification is published.
// Outputs:
// hello world!
// fn2 says: hello world!
// woo! mail!
~~~
- 前言
- 簡介
- 什么是設計模式?
- 設計模式的結構
- 編寫設計模式
- 反模式
- 設計模式的分類
- 設計模式分類概覽表
- JavaScript 設計模式
- 構造器模式
- 模塊化模式
- 暴露模塊模式
- 單例模式
- 觀察者模式
- 中介者模式
- 原型模式
- 命令模式
- 外觀模式
- 工廠模式
- Mixin 模式
- 裝飾模式
- 亨元(Flyweight)模式
- JavaScript MV* 模式
- MVC 模式
- MVP 模式
- MVVM 模式
- 最新的模塊化 JavaScript 設計模式
- AMD
- CommonJS
- ES Harmony
- JQuery 中的設計模式
- 組合模式
- 適配器模式
- 外觀模式
- 觀察者模式
- 迭代器模式
- 惰性初始模式
- 代理模式
- 建造者模式
- jQuery 插件的設計模式
- JavaScript 命名空間模式
- 總結
- 參考