在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ 設計模式之代理模式
代碼復用模式(避免篇)
S.O.L.I.D 五大原則之接口隔離原則 ISP
設計模式之狀態(tài)模式
JavaScript 核心(晉級高手必讀篇)
設計模式之建造者模式
JavaScript 與 DOM(上)——也適用于新手
設計模式之中介者模式
設計模式之裝飾者模式
設計模式之模板方法
設計模式之外觀模式
強大的原型和原型鏈
設計模式之構(gòu)造函數(shù)模式
揭秘命名函數(shù)表達式
深入理解J avaScript 系列(結(jié)局篇)
執(zhí)行上下文(Execution Contexts)
函數(shù)(Functions)
《你真懂 JavaScript 嗎?》答案詳解
設計模式之適配器模式
設計模式之組合模式
設計模式之命令模式
S.O.L.I.D 五大原則之單一職責 SRP
編寫高質(zhì)量 JavaScript 代碼的基本要點
求值策略
閉包(Closures)
對象創(chuàng)建模式(上篇)
This? Yes,this!
設計模式之代理模式
變量對象(Variable Object)
S.O.L.I.D 五大原則之里氏替換原則 LSP
面向?qū)ο缶幊讨话憷碚?/span>
設計模式之單例模式
Function 模式(上篇)
S.O.L.I.D 五大原則之依賴倒置原則 DIP
設計模式之迭代器模式
立即調(diào)用的函數(shù)表達式
設計模式之享元模式
設計模式之原型模式
根本沒有“JSON 對象”這回事!
JavaScript 與 DOM(下)
面向?qū)ο缶幊讨?ECMAScript 實現(xiàn)
全面解析 Module 模式
對象創(chuàng)建模式(下篇)
設計模式之職責鏈模式
S.O.L.I.D 五大原則之開閉原則 OCP
設計模式之橋接模式
設計模式之策略模式
設計模式之觀察者模式
代碼復用模式(推薦篇)
作用域鏈(Scope Chain)
Function 模式(下篇)
設計模式之工廠模式

設計模式之代理模式

介紹

代理,顧名思義就是幫助別人做事,GoF 對代理模式的定義如下:

代理模式(Proxy),為其他對象提供一種代理以控制對這個對象的訪問。

代理模式使得代理對象控制具體對象的引用。代理幾乎可以是任何對象:文件,資源,內(nèi)存中的對象,或者是一些難以復制的東西。

正文

我們來舉一個簡單的例子,假如dudu要送酸奶小妹玫瑰花,卻不知道她的聯(lián)系方式或者不好意思,想委托大叔去送這些玫瑰,那大叔就是個代理(其實挺好的,可以扣幾朵給媳婦),那我們?nèi)绾蝸碜瞿兀?/p>

// 先聲明美女對象
var girl = function (name) {
    this.name = name;
};
// 這是dudu
var dudu = function (girl) {
    this.girl = girl;
    this.sendGift = function (gift) {
        alert("Hi " + girl.name + ", dudu送你一個禮物:" + gift);
    }
};
// 大叔是代理
var proxyTom = function (girl) {
    this.girl = girl;
    this.sendGift = function (gift) {
        (new dudu(girl)).sendGift(gift); // 替dudu送花咯
    }
};

調(diào)用方式就非常簡單了:

var proxy = new proxyTom(new girl("酸奶小妹"));
proxy.sendGift("999朵玫瑰");

實戰(zhàn)一把

通過上面的代碼,相信大家對代理模式已經(jīng)非常清楚了,我們來實戰(zhàn)下:我們有一個簡單的播放列表,需要在點擊單個連接(或者全選)的時候在該連接下方顯示視頻曲介紹以及 play 按鈕,點擊 play 按鈕的時候播放視頻,列表結(jié)構(gòu)如下:

<h1>Dave Matthews vids</h1>
<p><span id="toggle-all">全選/反選</span></p>
<ol id="vids">
  <li><input type="checkbox" checked><a >Gravedigger</a></li>
  <li><input type="checkbox" checked><a >Save Me</a></li>
  <li><input type="checkbox" checked><a >Crush</a></li>
  <li><input type="checkbox" checked><a t Drink The Water</a></li>
  <li><input type="checkbox" checked><a >Funny the Way It Is</a></li>
  <li><input type="checkbox" checked><a >What Would You Say</a>
</li>
</ol>

我們先來分析如下,首先我們不僅要監(jiān)控 a 連接的點擊事件,還要監(jiān)控“全選/反選”的點擊事件,然后請求服務器查詢視頻信息,組裝 HTML 信息顯示在 li 元素的最后位置上,效果如下:

http://wiki.jikexueyuan.com/project/javascript-depth-understanding/images/17.png" alt="" />

然后再監(jiān)控play連接的點擊事件,點擊以后開始播放,效果如下:

http://wiki.jikexueyuan.com/project/javascript-depth-understanding/images/18.png" alt="" />

好了,開始,沒有 jQuery,我們自定義一個選擇器:

var $ = function (id) {
    return document.getElementById(id);
};

由于 Yahoo 的 json 服務提供了 callback 參數(shù),所以我們傳入我們自定義的 callback 以便來接受數(shù)據(jù),具體查詢字符串拼裝代碼如下:

var http = {
    makeRequest: function (ids, callback) {
        var url = 'http://query.yahooapis.com/v1/public/yql?q=',
            sql = 'select * from music.video.id where ids IN ("%ID%")',
            format = "format=json",
            handler = "callback=" + callback,
            script = document.createElement('script');
            sql = sql.replace('%ID%', ids.join('","'));
            sql = encodeURIComponent(sql);
            url += sql + '&' + format + '&' + handler;
            script.src = url;
        document.body.appendChild(script);
    }
};

代理對象如下:

var proxy = {
    ids: [],
    delay: 50,
    timeout: null,
    callback: null,
    context: null,
    // 設置請求的id和callback以便在播放的時候觸發(fā)回調(diào)
    makeRequest: function (id, callback, context) {
        // 添加到隊列dd to the queue
        this.ids.push(id);
        this.callback = callback;
        this.context = context;
        // 設置timeout
        if (!this.timeout) {
            this.timeout = setTimeout(function () {
                proxy.flush();
            }, this.delay);
        }
    },
    // 觸發(fā)請求,使用代理職責調(diào)用了http.makeRequest
    flush: function () {
        // proxy.handler為請求yahoo時的callback
        http.makeRequest(this.ids, 'proxy.handler'); 
        // 請求數(shù)據(jù)以后,緊接著執(zhí)行proxy.handler方法(里面有另一個設置的callback)
        // 清楚timeout和隊列
        this.timeout = null;
        this.ids = [];
    },
    handler: function (data) {
        var i, max;
        // 單個視頻的callback調(diào)用
        if (parseInt(data.query.count, 10) === 1) {
            proxy.callback.call(proxy.context, data.query.results.Video);
            return;
        }
        // 多個視頻的callback調(diào)用
        for (i = 0, max = data.query.results.Video.length; i < max; i += 1) {
            proxy.callback.call(proxy.context, data.query.results.Video[i]);
        }
    }
};

視頻處理模塊主要有 3 種子功能:獲取信息、展示信息、播放視頻:

var videos = {
    // 初始化播放器代碼,開始播放
    getPlayer: function (id) {
        return '' +
            '<object width="400" height="255" id="uvp_fop" allowFullScreen="true">' +
            '<param name="movie" value="http://d.yimg.com/m/up/fop/embedflv/swf/fop.swf"\/>' +
            '<param name="flashVars" value="id=v' + id + '&amp;eID=1301797&amp;lang=us&amp;enableFullScreen=0&amp;shareEnable=1"\/>' +
            '<param name="wmode" value="transparent"\/>' +
            '<embed ' +
            'height="255" ' +
            'width="400" ' +
            'id="uvp_fop" ' +
            'allowFullScreen="true" ' +
            'src="http://d.yimg.com/m/up/fop/embedflv/swf/fop.swf" ' +
            'type="application/x-shockwave-flash" ' +
            'flashvars="id=v' + id + '&amp;eID=1301797&amp;lang=us&amp;ympsc=4195329&amp;enableFullScreen=1&amp;shareEnable=1"' +
            '\/>' +
            '<\/object>';
                },
    // 拼接信息顯示內(nèi)容,然后在append到li的底部里顯示
    updateList: function (data) {
        var id,
            html = '',
            info;
        if (data.query) {
            data = data.query.results.Video;
        }
        id = data.id;
        html += '<img src="' + data.Image[0].url + '" width="50" \/>';
        html += '<h2>' + data.title + '<\/h2>';
        html += '<p>' + data.copyrightYear + ', ' + data.label + '<\/p>';
        if (data.Album) {
            html += '<p>Album: ' + data.Album.Release.title + ', ' + data.Album.Release.releaseYear + '<br \/>';
        }
        html += '<p><a class="play"  + id + '">&raquo; play<\/a><\/p>';
        info = document.createElement('div');
        info.id = "info" + id;
        info.innerHTML = html;
        $('v' + id).appendChild(info);
    },
    // 獲取信息并顯示
    getInfo: function (id) {
        var info = $('info' + id);
        if (!info) {
            proxy.makeRequest(id, videos.updateList, videos); //執(zhí)行代理職責,并傳入videos.updateList回調(diào)函數(shù)
            return;
        }
        if (info.style.display === "none") {
            info.style.display = '';
        } else {
            info.style.display = 'none';
        }
    }
};

現(xiàn)在可以處理點擊事件的代碼了,由于有很多 a 連接,如果每個連接都綁定事件的話,顯然性能會有問題,所以我們將事件綁定在 <ol> 元素上,然后檢測點擊的是否是a連接,如果是說明我們點擊的是視頻地址,然后就可以播放了:

$('vids').onclick = function (e) {
    var src, id;
    e = e || window.event;
    src = e.target || e.srcElement;
    // 不是連接的話就不繼續(xù)處理了
    if (src.nodeName.toUpperCase() !== "A") {
        return;
    }
    //停止冒泡
    if (typeof e.preventDefault === "function") {
        e.preventDefault();
    }
    e.returnValue = false;
    id = src.href.split('--')[1];
    //如果點擊的是已經(jīng)生產(chǎn)的視頻信息區(qū)域的連接play,就開始播放
    // 然后return不繼續(xù)了
    if (src.className === "play") {
        src.parentNode.innerHTML = videos.getPlayer(id);
        return;
    }
    src.parentNode.id = "v" + id;
    videos.getInfo(id); // 這個才是第一次點擊的時候顯示視頻信息的處理代碼
};

全選反選的代碼大同小異,我們就不解釋了:

$('toggle-all').onclick = function (e) {
    var hrefs, i, max, id;
    hrefs = $('vids').getElementsByTagName('a');
    for (i = 0, max = hrefs.length; i < max; i += 1) {
        // 忽略play連接
        if (hrefs[i].className === "play") {
            continue;
        }
        // 忽略沒有選擇的項
        if (!hrefs[i].parentNode.firstChild.checked) {
            continue;
        }
        id = hrefs[i].href.split('--')[1];
        hrefs[i].parentNode.id = "v" + id;
        videos.getInfo(id);
    }
};

總結(jié)

代理模式一般適用于如下場合:

  1. 遠程代理,也就是為了一個對象在不同的地址空間提供局部代表,這樣可以隱藏一個對象存在于不同地址空間的事實,就像 web service 里的代理類一樣。
  2. 虛擬代理,根據(jù)需要創(chuàng)建開銷很大的對象,通過它來存放實例化需要很長時間的真實對象,比如瀏覽器的渲染的時候先顯示問題,而圖片可以慢慢顯示(就是通過虛擬代理代替了真實的圖片,此時虛擬代理保存了真實圖片的路徑和尺寸。
  3. 安全代理,用來控制真實對象訪問時的權(quán)限,一般用于對象應該有不同的訪問權(quán)限。
  4. 智能指引,只當調(diào)用真實的對象時,代理處理另外一些事情。例如 C#里的垃圾回收,使用對象的時候會有引用次數(shù),如果對象沒有引用了,GC 就可以回收它了。

參考:《大話設計模式》