JavaScript设计模式(4)-桥接模式

桥接模式

在设计一个 Js API 时,可用来弱化它与使用它的类和对象之间的耦合

1. 事件监听器的回调函数

function getBeerById(id, callback) {
    asyncRequest('GET', 'beer.uri?id=' + id, function(res){
        callback(resp.responseText)
    })
}

function getBeerByIdBridge (e) {   // 桥接元素:事件监听器的回调函数

    // 避免把 this.id 耦合到函数 getBeerById 中
    getBeerById(this.id, function(beer) {
        console.log('Requested Beer: ' + beer)
    })
}

addEvent(element, 'click', getBeerByIdBridge);

2. 桥接性函数:特权函数

var Public = function() {
    var secret = 3;
    this.privilegedGetter = function() {
        return secret
    }
}

// usage
var o = new Public;
var data = o.privilegedGetter()

3. 用桥接模式联结多个类

var Class1 = function(a, b, c) {
    this.a = a;
    this.b = b;
    this.c = c;
}
var Class2 = function(d) {
    this.d = d;
}

var BridgeClass = function(a, b, c, d) {
    this.one = new Class1(a, b, c);
    this.two = new Class2(d)
}

4. 构建 XHR 连接队列

// 获取 xhr 对象函数
var asyncRequest = (function() {
    function handleReadyState(o, callback) {      // 其实也可以用 xhr.onreadystatechange 来实现而不用 setInterval 来监听 xhr 的 readyState
        var poll = window.setInterval(function(){
            if(o && o.readyState == 4) {
                window.clearInterval(poll);
                if(callback) {
                    callback(o)
                }
            }
        }, 50);
    }

    var getXHR = function() {
        var http;
        try {
            http = new XMLHttpRequest;
            getXHR = function() {           // memoizing
            return new XMLHttpRequest;
            }
        }catch(e) {
            var msxml = [
            'MSXML2.XMLHTTP',
            'MSXML2.XMLHTTP.3.0',
            '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) {
                    continue;
                }
            }
        }
        return http;
    };

    return function(method, url, callback, postData) {
        var http = getXHR();
        http.open(method, url, true);
        handleReadyState(http, callback);
        http.send(postData || null);
        return http;
    }
})()

Function.prototype.method = function(name, fn) {
    this.prototype[name] = fn;
    return this
}


// 实现队列
DED.Queue = function() {
    this.queue = [];
    this.retryCount = 3;
    this.currentRetry = 0;
    this.paused = false;
    this.timeout = 5000;
    this.conn = {};
    this.timer = {};
}

DED.Queue.method('flush', function(){
    if(!this.queue.length > 0) {   // 当队列长度等于 0 时进入 if
        return;
    }
    if(this.paused) {
        this.paused = false;
        return
    }
    var that = this;
    this.currentRetry++;

    // 如果在规定次数内,则继续重复请求,否则结束当前该请求
    var abort = function() {
        that.conn.abort();  // 终止该请求,readyState 属性将被置为 0
        if(that.currentRetry == that.retryCount) {
            // that.onFailure.fire();
            console.log('failure: ' + that.queue[0].url)
            that.currentRetry = 0;
        } else {
            that.flush();
        }
    }

    var callback = function (o) {
        document.getElementById('feed-readers').innerText = o.response
        console.log(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;
        }
        // 继续新的请求
        that.flush()
    }

    this.conn = asyncRequest(
        this.queue[0]['method'],
        this.queue[0]['url'],
        callback,
        this.queue[0]['params']
    )
    this.timer = window.setTimeout(abort, this.timeout);

}).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 = []
})

// usage
var q = new DED.Queue;
q.setRetryCount(3);
q.setTimeout(1000);
q.add({
    method: 'GET',
    'url': 'https://www.baidu.com',
});
q.add({
    method: 'GET',
    'url': 'https://www.baidu.com?xiaoming',
});

q.flush()

// 在真实使用中,可以在添加事件的时候使用桥接函数;
// 也可以提供一个动作调度函数,桥接用户操作所包含的输入信息并将其委托给恰当的处理代码。

5. 桥接模式的利与弊

  • 利:
    • 将抽象与其实现隔离开,有助于独立地管理软件的各个部分
    • Bug更容易查找
    • 促进代码的模块化,提高抽象的灵活度
    • 可以用来把一组类和函数连接起来,而且提供了一种借助于特权函数访问私有数据的手段
  • 弊:
    • 增加了函数调用次数,对性能有一些负面影响
    • 提高了系统的复杂度
    • 不可滥用

注意

转载、引用,但请标明作者和原文地址

posted @ 2018-03-02 11:28  另一个小菜头  阅读(174)  评论(0编辑  收藏  举报