JS實現監聽模式和觀察者模式
最近看阮一峰先生的[url=http://www.ruanyifeng.com/blog/2012/12/asynchronous_javascript.html]這篇[/url]文章,文章涉及到觀察模式,監聽模式相關的設計模式的內容,正好,我最近也用swt做個一個視訊批量上傳的桌面應用,在這個桌面應用的sdk中,有大量的監聽器介面,用來監聽該應用的很多元件上的事件,比如按鈕的點選事件、樹形元件節點的選中事件,等等。我為了實現該應用,也大量應用了監聽模式,譬如:檔案上傳進度的監聽,上傳列表選中行的事件監聽,軟體啟動時log4j初始化的監聽事件,等等。
[img]http://dl.iteye.com/upload/attachment/0078/5511/9bcdefec-7190-39d4-9758-05e99e70ef56.png[/img]
[img]http://dl.iteye.com/upload/attachment/0078/5513/a261a023-e2a1-3627-998c-975567481822.png[/img]
在該應用開發的過程中,我曾經思考過用觀察者模式,但最後為了應用程式碼維護的簡單性,所有的事件處理,都統一使用了監聽模式。實際上面提到的檔案上傳進度的監聽,上傳列表選中行的事件監聽,軟體啟動時log4j初始化的監聽事件,只有上傳列表選中行的事件監聽可以改為觀察者模式,原因是因為選中多行時,確實要同時去更新工具欄狀態和狀態列顯示的資訊。
為了對監聽模式和觀察者模式有一個複習,我回復了阮先生的部落格,參考:[url]http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html#comment-267332[/url],回覆是通過js實現一個監聽模式的例子。實際上,我後來發現這個例子有一些命名上的瑕疵。本想再寫一個觀察者模式的例子進行回覆,無奈阮先生的部落格的評論功能實在是太弱了,我監聽模式的例子就貼亂了,還煩勞他修改了一次。因此,我才決心寫兩篇部落格交代一下這兩個設計模式。當然了,這篇部落格我只打算寫兩個沒有什麼實際場景的小例子,下篇部落格,舉例一個真實的場景,用java和js分別給出實現程式碼。
請看監聽模式的程式碼示例:
[code]
// 事件物件
var Event = function(obj) {
this.obj = obj;
this.getSource = function() {
return this.obj;
}
}
// 監聽物件
var F2 = function() {
this.hander = function(event) {
var f1 = event.getSource();
console.log("f2 do something!");
f1.callback();
}
}
// 被監聽物件
var F1 = function() {
this.abc = function() {
console.log("f1 do something one!");
// 建立事件物件
var e = new Event(this);
// 釋出事件
this.f2.hander(e);
console.log("f1 do something two!");
}
this.on = function(f2) {
this.f2 = f2;
}
this.callback = function() {
console.log("f1 callback invoke!");
}
}
// 主函式
function main() {
var f1 = new F1();
var f2 = new F2();
// 加入監聽
f1.on(f2);
f1.abc();
}
// 執行主函式
main();
[/code]
監聽模式示例執行結果:
[quote]
f1 do something one!
f2 do something!
f1 callback invoke!
f1 do something two!
[/quote]
觀察者模式的程式碼示例:
[code]
// 觀察者物件1
var F2 = function() {
this.update = function(observable, obj) {
console.log("f2 do something!");
for (var i=0, len=obj.length; i<len; i++) {
console.log(obj[i]);
}
observable.callback();
}
}
// 觀察者物件2
var F3 = function() {
this.update = function(observable, obj) {
console.log("f3 do something!");
for (var i=0, len=obj.length; i<len; i++) {
console.log(obj[i]);
}
observable.callback();
}
}
// 被觀察物件
var F1 = function() {
// 儲存所有觀察者
var observers = [];
this.abc = function() {
console.log("f1 do something one!");
var datas = ["蘋果", "桃子", "香蕉"];
// 通知所有觀察者
this.notifyObservers(datas);
console.log("f1 do something two!");
}
this.addObserver = function(observer) {
observers.push(observer)
}
this.callback = function() {
console.log("f1 callback invoke!");
}
this.notifyObservers = function(arg){
if (observers.length == 0) {
return;
};
for (var i = 0, len = observers.length; i < len; i++) {
observers[i].update(this, arg);
}
}
}
// 主函式
function main() {
var f1 = new F1();
var f2 = new F2();
var f3 = new F3();
// 加入觀察者
f1.addObserver(f2);
f1.addObserver(f3);
f1.abc();
}
// 執行主函式
main();
[/code]
觀察者模式示例執行結果:
[quote]
f1 do something one!
f2 do something!
蘋果
桃子
香蕉
f1 callback invoke!
f3 do something!
蘋果
桃子
香蕉
f1 callback invoke!
f1 do something two!
[/quote]
總結:
1、在觀察者模式示例中,被觀察的物件有兩個觀察者,因此兩個觀察者的邏輯被各自呼叫了;在監聽模式示例中,被監聽的物件只有一個監聽者,因此只有一個監聽者邏輯被呼叫了。監聽模式示例中的監聽者也可以有多個,但通知的時候需要逐一通知,比較麻煩,而觀察者就方便多了,所以,當一個物件只有一個需要通知的物件時,使用監聽者模式比較簡單,而當需要通知的物件比較多時,採用觀察者模式比較簡單明瞭,這些要結合相應的業務場景,譬如,郵件列表的訂閱就適合用觀察者模式。
2、這兩種模式都使用了回撥的機制,唯一區別不同的是,監聽模式使用一個Event物件來保留回撥的鉤子(事件源處傳入的物件,一般是被監聽者本身),而觀察者模式沒有抽象Event事件物件,使用引數的方式將鉤子傳到觀察者,並附帶傳入了一些其他的資訊。因此,觀察者模式和監聽者模式都是使用回撥機制,其設計思想異曲同工。
3、這兩種模式都是採用了物件之間組合的方式進行職責解耦,這是軟體設計的指導性思想,無論我們是否很精確的實現這兩種設計模式,只要在設計中把握儘量採用組合方式,我們的軟體結構就會相對比較清晰,耦合度就相對比較低了,這是這兩種設計模式給我們的啟示!
下篇我們通過實際的例子,使用Js和Java複習一下這兩種設計模式!
[color=gray]如果您覺得本文對您有益,請點選博文後的google廣告,對作者表示支援,謝謝![/color]