js實現觀察者模式


基本概念介紹

觀察者(observer) 模式廣泛用於客戶端Javascript編程中。所有的瀏覽器事件都是該模式的例子。它的另一個名字也稱為自定義事件(custom events),與那些由瀏覽器觸發的事件相比,自定義事件表示是由你編程實現的事件。此外,該模式的另一個別名也稱為訂閱/發布(subscriber/publisher)模式。

設計該模式背后的主要動力是促進形成松散耦合。在這種模式中,並不是一個對象調用另一個對象的方法,而是一個對象訂閱另一個對象的特定活動並在狀態改變后獲得通知。訂閱者也稱為觀察者,而補觀察的對象稱為發布者或主題。當發生了一個重要的事件時,發布者將會通知(調用)所有訂閱者並且可能經常以事件對象的形式傳遞消息。

示例:雜志訂閱

假設有一個發布者paper,它每天出版報紙及月刊雜志。訂閱者joe將被通知任何時候所發生的新聞。

該paper對象需要一個subscribers(topics )屬性,該屬性是一個存儲所有訂閱者的數組。訂閱行為只是將其加入到這個數組中。當一個事件發生時,paper將會循環遍歷訂閱者列表並通知它們。通知意味着調用訂閱者對象的某個方法。故當用戶訂閱信息時,該訂閱者需要向paper的subscribe()提供它的其中一個方法。

paper也提供了unsubscribe()方法,該方法表示從訂閱者數組(即subscribers屬性)中刪除訂閱者。paper最后一個重要的方法是publish(),它會調用這些訂閱者的方法,總而言之,發布者對象paper需要具有以下這些成員:

1.subscribers 一個數組 2.subscribe() 將訂閱者添加到subscribers數組中 3.unsubscribe() 從subscribers數組中刪除訂閱者 4.publish() 循環遍歷subscribers數組中的每一個元素,並且調用他們注冊時所提供的方法

所有這三種方法都需要一個topic參數,因為發布者可能觸發多個事件(比如同時發布一本雜志和一份報紙)而用戶可能僅選擇訂閱其中一種,而不是另外一種。

由於這些成員對於任何發布者對象都是通用的,故將它們作為獨立對象的一個部分來實現是很有意義的。那樣我們可將其復制到任何對象中,並將任意給定對象變成一個發布者。

JS里對觀察者模式的實現是通過回調來實現的,我們來先定義一個pubsub對象,其內部包含了3個方法:訂閱、退訂、發布。

var pubsub = {};
(function (q) {

    var topics = {}, // 回調函數存放的數組
        subUid = -1;
    // 發布方法
    q.publish = function (topic, args) {

        if (!topics[topic]) {
            return false;
        }

        setTimeout(function () {
            var subscribers = topics[topic],
                len = subscribers ? subscribers.length : 0;

            while (len--) {
                subscribers[len].func(topic, args);
            }
        }, 0);

        return true;

    };
    //訂閱方法
    q.subscribe = function (topic, func) {

        if (!topics[topic]) {
            topics[topic] = [];
        }

        var token = (++subUid).toString();
        topics[topic].push({
            token: token,
            func: func
        });
        return token;
    };
    //退訂方法
    q.unsubscribe = function (token) {
        for (var m in topics) {
            if (topics[m]) {
                for (var i = 0, j = topics[m].length; i < j; i++) {
                    if (topics[m][i].token === token) {
                        topics[m].splice(i, 1);
                        return token;
                    }
                }
            }
        }
        return false;
    };
} (pubsub));

使用方式如下:

//來,訂閱一個
pubsub.subscribe('example1', function (topics, data) {
    console.log(topics + ": " + data);
});

//發布通知
pubsub.publish('example1', 'hello world!');
pubsub.publish('example1', ['test', 'a', 'b', 'c']);
pubsub.publish('example1', [{ 'color': 'blue' }, { 'text': 'hello'}]);

試試多個訂閱者訂閱同個主題:

//來,訂閱一個
pubsub.subscribe('example1', function (topics, data) {
    console.log(topics + ": " + data);
});
//來,再訂閱一個
pubsub.subscribe('example1', function (topics, data) {
    console.log(topics + "******* " + data);
});

//發布通知
pubsub.publish('example1', 'hello world!');

輸出:

example1***** hello world!
example1: hello world!

參考:http://www.2cto.com/kf/201210/163500.html

http://www.cnblogs.com/TomXu/archive/2012/03/02/2355128.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM