javascript 代理模式(通俗易懂)

所謂的的代理模式就是爲一個對象找一個替代對象,以便對原對象進行訪問。前端

使用代理的緣由是咱們不肯意或者不想對原對象進行直接操做,咱們使用代理就是讓它幫原對象進行一系列的操做,等這些東西作完後告訴原對象就好了。就像咱們生活的那些明星的助理經紀人同樣。git

咱們舉一個明星買鞋子的例子。github

1.明星本身去買鞋。設計模式

// 定義一個鞋子類
var Shoes = function(name){
	this.name = name;
};

Shoes.prototype.getName = function() {
	return this.name;
};

// 定義一個明星對象
var star = {
	buyShoes: function(shoes) {
		console.log('買到了一雙' + shoes.getName());
	}
}

star.buyShoes(new Shoes('皮鞋')); // "買到了一雙皮鞋"
複製代碼

固然了,想買鞋這種事,通常都會交給助理去作。緩存

2.明星讓助理代本身去買鞋。bash

// 定義一個鞋子類
var Shoes = function(name){
	this.name = name;
};

Shoes.prototype.getName = function() {
	return this.name;
};

// 定義一個助理對象
 
var assistant = {
	buyShoes: function(shoes) {
		star.buyShoes(shoes.getName())
	}
};

// 定義一個明星對象
var star = {
	buyShoes: function(name) {
		console.log('買到了一雙' + name);
	}

};

assistant.buyShoes(new Shoes('高跟鞋')); // "買到了一雙高跟鞋"
複製代碼

怎麼樣,代理就是這麼簡單,可能到這裏有的同窗會比較疑惑,代理的實現結果不是和不使用同樣嗎?是的,同樣的實現結果是必須的,可是,值用代理並非咱們看到的那樣將簡單的事情複雜化了,代理的使用場景固然不是這種簡單的場景,而是針對一些比較複雜或特殊的狀況使用,這裏只是爲了舉例說明代理的實現。下面就介紹一些使用場景。網絡

代理使用場景

繼續上面的明星買鞋子的問題。在生活中咱們會遇到商店在營業時間,而你在工做時間,因爲要掙錢同時又要花錢,因此,會找一個代理;就像春節快到了,你沒時間或者搶不到票,就會找票販子同樣;像如今的代購,則是你不能出國,或者對國外不瞭解,就找能出國,對國外瞭解的人幫你買東西同樣。咱們知道每家商店都有本身的營業時間和休息時間,這裏咱們用(8:00~20:00)算做營業時間。app

// 定義一個鞋子類
var Shoes = function(name){
	this.name = name;
};

Shoes.prototype.getName = function() {
	return this.name;
};
// 添加了一個business方法,經過當前的時間來判斷是否能買到鞋子。
Shoes.prototype.business = function() {
	var curTime = new Date().getHours();
	return  curTime >= 8 && curTime <= 20 ? that.getName() : '"非營業時間!"';
	
}

// 定義一個助理對象
var assistant = {
	buyShoes: function(shoes) {
		star.buyShoes(shoes.getName())
	}
};

// 定義一個明星對象
var star = {
	buyShoes: function(name) {
		console.log('買到了一雙' + name);
	}
};

assistant.buyShoes(new Shoes('高跟鞋')); // "買到了一雙高跟鞋"
複製代碼

保護代理

助理做爲明星的代理,不只能夠幫助明星買東西,同時還有幫助明星過濾的東西的職責,好比說,有粉絲要送明星花(不是什麼樣的花都收的),有人要找明星代言廣告(不是什麼樣的廣告都代言的)。異步

// 定義一個廣告類
var Ad = function(price){
	this.price = price;
};

Ad.prototype.getPrice = function() {
	return this.price;
};

// 定義一個助理對象
var assistant = {
	init: function(ad) {
		var money = ad.getPrice();
		if(money > 300) {
			this.receiveAd(money);
		} else {
			this.rejectAd();
		}
	},
	receiveAd: function(price) {
		star.receiveAd(price);
	},
	rejectAd: function() {
		star.rejectAd();
	}
};

// 定義一個明星對象
var star = {
	receiveAd: function(price) {
		console.log('廣告費' + price + '萬元');
	},
	rejectAd: function() {
		console.log('拒絕小製做!');
	}
};

assistant.init(new Ad(5)); // "拒絕小製做!"
assistant.init(new Ad(500)); // "廣告費500萬元"
複製代碼

像這種明星向助理受權,如:什麼樣價位的廣告能夠接,什麼樣的鮮花能夠接等等。這樣將一些業務的處理交給助理或者經紀人處理,而本身則位於幕後,無疑給本身減小了沒必要要的麻煩,這樣明星就處於一種保護狀態。在現實生活中的例子比比皆是,一樣在咱們的程序語言開發中也是比較常見,尤爲是網絡和進程這方面,相信作過nodjs開發的同窗或多或少會遇到。函數

虛擬代理

在開發中,咱們每每將 new Ad('5') 這個對象的實例化操做,放到函數內部執行,這樣的操做會減小沒必要要的實例化對象的開銷,形成資源的浪費。這種使用的狀況咱們將之成爲虛擬代理。

下面就介紹一個常見的虛擬代理——圖片的預加載。

圖片預加載是一種常見的前端技術,因爲圖片過大或者網絡不佳,咱們不會直接給某個img標籤節點設置src屬性,而是使用一張loading圖片做爲佔位符,而後用異步的方式來家在加載圖片,等到圖片加載完畢,咱們再把它填充到img的節點裏。

var preImage = (function() {
	var imgNode = document.createElement('img');
	document.body.appendChild(imgNode);
	var img = new Image; 
    img.onload = function() {
    	imgNode.src = img.src;
    }; 
 
    return {
    	setSrc: function(src) {
    		imgNode.src = '../loading.gif';
    		img.src = src;
    	}
    }
})(); 
 
preImage.setSrc('https://cn.bing.com/az/hprichbg/rb/TadamiTrain_ZH-CN13495442975_1920x1080.jpg'); 
複製代碼

到這裏,圖片的預加載功能已經實現,可是每每體現一段代碼的是否更優秀,是看你的代碼是否易於維護,特別是對於海量的代碼。第一點,這段代碼不符合單一職責,咱們把負責圖片預加載的功能,對img元素的處理放在了一個函數體內,尤爲是沒有將代碼變化的部分和未變化的部分分開;第二點,就是未來咱們的網速很是好,咱們不用再擔憂因爲網絡不佳而形成的顯示效果問題,那麼關於圖片預加載的功能就要去掉。

咱們能夠嘗試使用代理來實現,代碼以下:

var myImage = (function() {
	var imgNode = document.createElement('img');
	document.body.appendChild(imgNode);
	return {
    	setSrc: function(src) {
    		imgNode.src = src;
    	}
    }
})();

var preImage = (function() {
	var img = new Image; 
    img.onload = function() {
    	myImage.setSrc = img.src;
    }; 
 
    return {
    	setSrc: function(src) {
    		myImage.setSrc('../loading.gif');
    		img.src = src;
    	}
    }
})(); 
 
preImage.setSrc('https://cn.bing.com/az/hprichbg/rb/TadamiTrain_ZH-CN13495442975_1920x1080.jpg'); 
複製代碼

這樣咱們就將圖片預加載和爲img元素節點設置src分開來。

代理和被代理對象的一致性

由於代理要實現和被代理對象實際處理同樣的效果,因此,在實現代理對象時,原對象有的方法,代理對象同樣有,這樣能夠保證,用戶在操做代理對象時就像在操做原對象同樣。

緩存代理

緩存代理就是將代理加緩存,下面是一個求和的例子:

var multAdd = function() {
	var res = 0;
	for (var i = 0, l = arguments.length; i < l; i++) {
		res = res + arguments[i]
	}

	return res;
};

var proxyAdd = (function() {
	var cache = {};
	return function() {
		var args = Array.prototype.join.call(arguments, ',');
		if(args in cache) {
			return cache[args];
		}
		return caches[args] = multAdd.apply(this, arguments);
	}
})();

proxyAdd(1, 2, 3); // 6
proxyAdd(1, 2, 3); // 6
複製代碼

咱們不用代理固然也能實現緩存就和,可是爲了達到單一職責,咱們可讓multAdd實現求和,而緩存則放在代理中來實現。

固然,還有其餘的分類代理,好比,智能代理,遠程代理。可是在JavaScript中咱們使用最多,也最多見的就是虛擬代理和緩存代理。

設計模式週週講

相關文章
相關標籤/搜索