JS設計模式初識(三)-代理模式

1、定義

代理模式是爲一個對象提供一個代用品或佔位符,以便控制對它的訪問。緩存

3.1 基本概念

代理模式是一種很是有意義的模式,在生活中能夠找到不少代理模式的場景。好比,明星都 有經紀人做爲代理。若是想請明星來辦一場商業演出,只能聯繫他的經紀人。經紀人會把商業演 出的細節和報酬都談好以後,再把合同交給明星籤。代理模式的關鍵是,當客戶不方便直接訪問一個對象或者不知足須要的時候,提供一個替身對象來控制對這個對象的訪問,客戶實際上訪問的是替身對象。替身對象對請求作出一些處理以後,再把請求轉交給本體對象。bash

圖: 3-1 不使用代理模式

圖 3-2 使用代理模式

3.2 簡單代理模式

3.2.1 基本代理實現

小明同窗喜歡大A, 他們之間有一個共同大朋友B,因而小明同窗經過代理B給大A女神送🌹,以提升本身追求女神的成功率。B會在大A心情愉悅的時候給A送花。app

function Flower() {}
    const xiaoMing = {
        sendFlower: function(target) {
            target.recivedFlower(flower);
        }
    }
    // 大A女神
    const A = {
        recivedFlower: (flower) => {
            console.log('A recived => ',flower);
        },
        listenGoodMoon: (fn) => { //十秒後心情變好
            setTimeout(() => {
                fn && fn();
            }, 5000);
        }
    }
    // 代理B 監聽A心情變好的時候送出花
    const B = {
        recivedFlower: (flower) => {
            A.listenGoodMoon(() => {
                const flower = new Flower(); // 延遲建立對象
                A.recivedFlower(flower);
            })
        }
    }

    xiaoMing.sendFlower(B);
複製代碼
3.2.2 保護代理和虛擬代理
  • 保護代理: 代理 B 能夠幫助A過濾掉一些請求,好比送花的人中年齡太大的或者沒有寶馬的,這種請求就能夠直接在代理 B 處被拒絕掉。這種代理叫做保護代理。A 和 B 一個充當白臉,一個充當黑臉。白臉 A 繼續保持良好的女神形象,不但願直接拒絕任何人,因而找了黑臉 B 來控制對 A 的訪問。函數

  • 虛擬代理: new Flower 也是一個代價昂貴的操做, 那麼咱們能夠把 new Flower 的操做交給代理 B 去執行,代理 B 會選擇在 A 心情好時再執行 new Flower,這是代理模式的另外一種形式,叫做虛擬代理。虛擬代理把一些開銷很大的對象,延遲到 真正須要它的時候纔去建立。優化

3.3 虛擬代理實現惰性加載圖片

// 虛擬代理實現惰性加載圖片 , 先展現展位圖
    const myImage = (function(){
        const imgNode = document.getElementById('img');
        document.body.appendChild(imgNode);
        return {
            setSrc: (src) => {
                imgNode.src = src;
            }
        }
    })();

    const proxyImage = (function(){
        const img = new Image();
        img.onload = function() {
            myImage.setSrc(this.src);
        }
        return {
            setSrc: function(src) {
                myImage.setSrc('file://xxx.png'); // 佔位圖
                img.src = src;
            }
        }
    })();

    proxyImage.setSrc('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1560084344566&di=1715e9c36a3ea72ebadea7f3dece0d50&imgtype=0&src=http%3A%2F%2F02.imgmini.eastday.com%2Fmobile%2F20170909%2F20170909181904_24a9ff37f7c98886769a9e85f15b7d60_1.jpeg');
複製代碼

如今咱們經過 proxyImage 間接地訪問 MyImage。proxyImage 控制了客戶對 MyImage 的訪問,並 且在此過程當中加入一些額外的操做,好比在真正的圖片加載好以前,先把 img 節點的 src 設置爲 一張本地的 loading 圖片。ui

3.4 單一職責原則

單一職責原則指的是,就一個類(一般也包括對象和函數等)而言,應該僅有一個引發它變 化的緣由。若是一個對象承擔了多項職責,就意味着這個對象將變得巨大,引發它變化的緣由可 能會有多個。面向對象設計鼓勵將行爲分佈到細粒度的對象之中,若是一個對象承擔的職責過多,等於把這些職責耦合到了一塊兒,這種耦合會致使脆弱和低內聚的設計。當變化發生時,設計可能會遭到意外的破壞。this

3.5 緩存代理

3.5.1 基本實現
// 緩存代理
    const mult = function() {
        let result = 1;
        for (let i=0; i<arguments.length; i++) {
            result *= arguments[i];
        }
        return result;
    }
    const proxyMult = (function() {
        const cache = {};
        return function() {
            const argsStr = Array.prototype.join.call(arguments, ',');
            if (argsStr in cache) {
                return cache[argsStr];
            }
            return cache[argsStr] = mult.call(this, arguments);
        }
    })();
    proxyMult(1,2,3,4);
複製代碼
3.5.2 優化代碼
// 優化代碼
    const mult = (...args) => {
        return args.reduce((rs, item) => rs * item);
    }

    const proxyMult = (function() {
        const cache = {};
        return (...args) => {
            const argsStr = args.join(',');
            let result = cache[argsStr];
            return caches[argsStr] = result ? result : mult(...args);
        };
    })();
複製代碼
3.5.3 衍生: 使用高階函數來建立緩存代理工廠
// 使用高階函數來建立緩存代理工廠
    const mult = (...args) => args.reduce((rs, item) => rs * item);
    const sum = (...args) => args.reduce((rs, item) => rs + item);
    // 高階函數
    const createProxyFactory = (fn = ()=>{}) => {
        const cache = {};
        return (...args) => {
            const argsStr = args.join(',');
            const result = !isEmpty(cache) && cache[argsStr];
            return cache[argsStr] = result ? result : fn(...args);
        }
    }
    const proxyMult = createProxyFactory(mult);
    proxyMult(1,2,3,5);
複製代碼

2、總結

代理模式包括許多小分類,在 JavaScript 開發中最經常使用的是虛擬代理和緩存代理。雖然代理 模式很是有用,但咱們在編寫業務代碼的時候,每每不須要去預先猜想是否須要使用代理模式。 當真正發現不方便直接訪問某個對象的時候,再編寫代理也不遲。spa

相關文章
相關標籤/搜索