Observer模式是GOF design pattern裡面很基本的模式,他的目的主要是讓一個物件狀態改變時,多個相關物件可以被通知。Java就大量使用這個模式來處理事件。
結構
Javascript中,Observer的實作方法大致上符合GOF裡面提到的方法。以下用一個剛好可以滿足Observer的需要的功能的簡單的例子來示範;裡面用了三個物件:Observer、Observable、CustomEvent來協作,Observer把它做成一個像是CustomEvent的內部物件用來做事件管理的單位,事件透過CustomEvent來註冊,Observable狀態改變時,就會通知Observer:
<script>
(function(){
function Observer(fn, type) {
this.uid = this.toString() + new Date().getTime();
this.update = function(e) {
if (e.type == type) {
fn(e);
}
};
}
$ = {};
$.EventType = {
noEvent: 0,
Type1: 1,
Type2: 2
};
$.CustomEvent = new (function() {
var subscribed = {};
this.registerEvent = function (o, fn, type) {
var ob = new Observer(fn, type);
o.subscribe(ob);
subscribed[ob.uid] = ob;
return ob.uid;
};
this.unregisterEvent = function (o, uid) {
o.unsubscribe(subscribed[uid]);
delete subscribed[uid];
};
})();
$.Observable = function () {
var subscribers = {};
var state = $.EventType.noEvent;
this.notify = function() {
for (var i in subscribers) {
subscribers[i].update({type: state});
}
};
this.subscribe = function(s, type) {
if (!subscribers[s.uid]) {
subscribers[s.uid] = s;
}
};
this.unsubscribe = function(s) {
if (subscribers[s.uid]) {
delete subscribers[s.uid];
}
};
this.getState = function() {return state;};
this.setState = function(s) {
state = s;
this.notify();
};
};
})();
var obj = new $.Observable();
var eid = $.CustomEvent.registerEvent(
obj,
function(e){alert("event type of: " + e.type);},
$.EventType.Type1);
obj.setState($.EventType.Type1);
obj.setState($.EventType.Type2);
$.CustomEvent.unregisterEvent(obj, eid);
obj.setState($.EventType.Type1);
</script>
以細節來說還有進步空間,但是可以看到簡單的Observer模式運作的全貌。
應用
在Javascript中,Observer模式最常用的地方,恐怕還是用來管理自訂的事件。把上面的程式做一些調整,然後需要使用自訂事件的物件繼承Observable,接下來就可以透過CustomEvent來做自訂事件的管理。
例如YUI3,就定義了DomEVent、CustomEvent以及Event三個模組,其中DomEvent用來包裝DOM的事件、CustomEvent則應用Observer模式來實作自訂事件,最後Event使用facade模式把這兩個包裝成一致的介面。