介紹
橋接模式(Bridge)將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
正文
橋接模式最常用在事件監控上,先看一段代碼:
這個例子看起來有些簡單,我們再來一個復雜點的實戰例子。
實戰XHR連接隊列
我們要構建一個隊列,隊列里存放了很多ajax請求,使用隊列(queue)主要是因為要確保先加入的請求先被處理。任何時候,我們可以暫停請求、刪除請求、重試請求以及支持對各個請求的訂閱事件。
基礎核心函數
在正式開始之前,我們先定義一下核心的幾個封裝函數,首先第一個是異步請求的函數封裝:
    var getXHR = function () {
        var http;
        try {
            http = new XMLHttpRequest;
            getXHR = function () {
                return new XMLHttpRequest;
            };
        }
        catch (e) {
            var msxml = [
                        'MSXML2.XMLHTTP.3.0',
                        'MSXML2.XMLHTTP',
                        'Microsoft.XMLHTTP'
                        ];
            for (var i = 0, len = msxml.length; i < len; ++i) {
                try {
                    http = new ActiveXObject(msxml[i]);
                    getXHR = function () {
                        return new ActiveXObject(msxml[i]);
                    };
                    break;
                }
                catch (e) { }
            }
        }
        return http;
    };
    return function (method, uri, callback, postData) {
        var http = getXHR();
        http.open(method, uri, true);
        handleReadyState(http, callback);
        http.send(postData || null);
        return http;
    };
})();
上述封裝的自執行函數是一個通用的Ajax請求函數,相信屬性Ajax的人都能看懂了。
接下來我們定義一個通用的添加方法(函數)的方法:
if (!Array.prototype.filter) {
    Array.method('filter', function (fn, thisObj) {
        var scope = thisObj || window;
        var a = [];
        for (var i = 0, len = this.length; i < len; ++i) {
            if (!fn.call(scope, this[i], i, this)) {
                continue;
            }
            a.push(this[i]);
        }
        return a;
    });
}
觀察者系統
觀察者在隊列里的事件過程中扮演著重要的角色,可以隊列處理時(成功、失敗、掛起)訂閱事件:
DED.util.Observer.prototype = {
    subscribe: function (fn) {
        this.fns.push(fn);
    },
    unsubscribe: function (fn) {
        this.fns = this.fns.filter(
            function (el) {
                if (el !== fn) {
                    return el;
                }
            }
            );
            },
    fire: function (o) {
        this.fns.forEach(
            function (el) {
                el(o);
            }
            );
    }
};
隊列主要實現代碼
首先訂閱了隊列的主要屬性和事件委托:
    // 核心屬性,可以在外部調用的時候進行設置
 this.retryCount = 3;
    this.currentRetry = 0;
    this.paused = false;
    this.timeout = 5000;
    this.conn = {};
    this.timer = {};
};
然后通過DED.Queue.method的鏈式調用,則隊列上添加了很多可用的方法:
        if (this.paused) {
            this.paused = false;
            return;
        }
        var that = this;
        this.currentRetry++;
        var abort = function () {
            that.conn.abort();
            if (that.currentRetry == that.retryCount) {
                that.onFailure.fire();
                that.currentRetry = 0;
            } else {
                that.flush();
            }
        };
        this.timer = window.setTimeout(abort, this.timeout);
        var callback = function (o) {
            window.clearTimeout(that.timer);
            that.currentRetry = 0;
            that.queue.shift();
            that.onFlush.fire(o.responseText);
            if (that.queue.length == 0) {
                that.onComplete.fire();
                return;
            }
            // recursive call to flush
 that.flush();
};
        this.conn = asyncRequest(
            this.queue[0]['method'],
            this.queue[0]['uri'],
            callback,
            this.queue[0]['params']
            );
    }).
    method('setRetryCount', function (count) {
        this.retryCount = count;
    }).
    method('setTimeout', function (time) {
        this.timeout = time;
    }).
    method('add', function (o) {
        this.queue.push(o);
    }).
    method('pause', function () {
        this.paused = true;
    }).
    method('dequeue', function () {
        this.queue.pop();
    }).
    method('clear', function () {
        this.queue = [];
    });
簡單調用
q.add({
    method: 'GET',
    uri: '/path/to/file.php?ajax=true&woe=me'
});
// flush隊列
q.flush();
// 暫停隊列,剩余的保存
q.pause();
// 清空.
q.clear();
// 添加2個請求.
q.add({
    method: 'GET',
    uri: '/path/to/file.php?ajax=true'
});
q.add({
    method: 'GET',
    uri: '/path/to/file.php?ajax=true&woe=me'
});
// 從隊列里刪除最后一個請求.
q.dequeue();
// 再次Flush
q.flush();
橋接呢?
上面的調用代碼里并沒有橋接,那橋呢?看一下下面的完整示例,就可以發現處處都有橋哦:
總結
橋接模式的優點也很明顯,我們只列舉主要幾個優點:
1.分離接口和實現部分,一個實現未必不變地綁定在一個接口上,抽象類(函數)的實現可以在運行時刻進行配置,一個對象甚至可以在運行時刻改變它的實現,同將抽象和實現也進行了充分的解耦,也有利于分層,從而產生更好的結構化系統。
2.提高可擴充性
3.實現細節對客戶透明,可以對客戶隱藏實現細節。
同時橋接模式也有自己的缺點:
大量的類將導致開發成本的增加,同時在性能方面可能也會有所減少。
新聞熱點
疑難解答