js設計模式——代理模式(讀書JavaScript設計模式與開發實戰筆記02)

代理模式

代理模式顧名思義,就是通過一個代理去處理問題,例如黑道頭子去買軍火,一般都是讓自己的頭號手下去買,自己不參與實際交易~~

虛擬代理

我們先從常見的圖片佔位圖片代理來說明。
通常情況下,我們加載圖片的姿勢是這樣的。

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
</head>

<body>
	<!-- https://wallpapers.wallhaven.cc/wallpapers/full/wallhaven-747189.jpg -->
	<!-- https://www.baidu.com/img/xinshouye_4d9e7ecaa1b5f78475bf13965c6142d1.png -->
	<img id="image" src="" alt="">
	<script>
		var mgImage = (function(){
			var img = document.getElementById('image');
			// 因爲我們需要一個方法 去供代理使用,所以這裏返回的是對象。
			return {
				setImage: function(src){
					img.src = src;
				}
			}
		})();
		mgImage.setImage('https://wallpapers.wallhaven.cc/wallpapers/full/wallhaven-747189.jpg');

	</script>
</body>

</html>

沒錯,打開非常卡,因爲我用的是一個外國網站的圖片。
使用代理佔位圖片來加載就是一個非常好的方法。如下:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
</head>

<body>
	<!-- https://wallpapers.wallhaven.cc/wallpapers/full/wallhaven-747189.jpg -->
	<!-- https://www.baidu.com/img/xinshouye_4d9e7ecaa1b5f78475bf13965c6142d1.png -->
	<img id="image" src="" alt="">
	<script>
		var mgImage = (function(){
			var img = document.getElementById('image');
			return {
				setImage: function(src){
					// 2.設置成功,顯示佔位圖片。
					img.src = src;
				}
			}
		})();

		var poxyImge = (function(){
			// 怎樣判斷我們需要的圖片加載完成,首先創建一個圖片實例poxyImg,用onload判斷。
			var poxyImg= new Image();
			poxyImg.onload = function(){
				// 4.當真實圖片地址加載完畢,添加到body的img標籤裏,完成代理。
				mgImage.setImage(this.src)
			}
			return {
				setImage: function(src) {
					// 1.先給img加載佔位圖片。
					mgImage.setImage('https://www.baidu.com/img/xinshouye_4d9e7ecaa1b5f78475bf13965c6142d1.png');
					// 3.給poxyImg實例添加真實圖片地址
					poxyImg.src =src;
				}
			}
		})()
		poxyImge.setImage('https://wallpapers.wallhaven.cc/wallpapers/full/wallhaven-747189.jpg');

	</script>
</body>

</html>

當然我們也可以放在一個函數當中,這樣就違反了單一原則和開放封閉原則,上面的代理模式,如果我們以後不需要這個圖片佔位,直接用mgImage函數調用方法就可以了。
如果不用代理模式如下:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
</head>

<body>
	<!-- https://wallpapers.wallhaven.cc/wallpapers/full/wallhaven-747189.jpg -->
	<!-- https://www.baidu.com/img/xinshouye_4d9e7ecaa1b5f78475bf13965c6142d1.png -->
	<img id="image" src="" alt="">
	<script>
		var mgImage= (function(){
			var img = document.getElementById('image');
			var poxyImg = new Image;	
			poxyImg.onload = function(){
				img.src = this.src
			}
			return {
				setImage: function(src){
					img.src = 'https://www.baidu.com/img/xinshouye_4d9e7ecaa1b5f78475bf13965c6142d1.png';
					poxyImg.src = src;
				}
			}
		})();	
		mgImage.setImage('https://wallpapers.wallhaven.cc/wallpapers/full/wallhaven-747189.jpg')
	</script>
</body>

</html>

這樣也能完成,但是對於以後的維護成本將會提升很多,因爲要去mgImage函數中去修改原有的代碼,是非常不划算的,而且容易產生BUG。

緩存代理

常常用於比較大的計算開銷,如果傳入的參數一致,則直接返回結果,無需計算。
比方說如下栗子,

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
</head>

<body>
	<script>
		var mult =  function () {
			console.log('start');
			var a = 1;
			for (var i = 0; i < arguments.length; i++) {
				a = a*arguments[i];
			}
			return a;
		}
		var poxyMult = (function () {
			var cache = {};
			return function () {
				// 定義對象KEY
				var args = Array.prototype.join.call(arguments, ',');
				// 判斷KEY是否存在,不存在,新建一個key value
				if (!cache[args]) {
					cache[args] = mult.apply(this, arguments)
				}
				// 返回當前key 對應的value
				return cache[args];
			}
		})()
		var num = poxyMult(1,2,4,9); // 72
		var num1 = poxyMult(1,2,4,9); //72
	</script>
</body>

</html>

上面就使用了緩存代理,如果傳入參數一樣的情況下,會直接返回cache裏面的值,當然這樣寫的話,我們只能計算乘積,其實我們可以進行解耦,在原先的poxyMult中,我們不僅進行了緩存,還把mult函數直接綁定在裏面,這樣是不好的,我們改寫下。

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
</head>

<body>
	<script>
		var mult =  function () {
			console.log('start');
			var a = 1;
			for (var i = 0; i < arguments.length; i++) {
				a = a*arguments[i];
			}
			return a;
		}
		var createProxyFactory = function (fn) {
			var cache = {};
			return function () {
				var args = Array.prototype.join.call(arguments, ',');
				if (!cache[args]) {
					cache[args] = fn.apply(this, arguments)
				}
				return cache[args];
			}
		}
		var add =  function () {
			console.log('start');
			var a = 1;
			for (var i = 0; i < arguments.length; i++) {
				a = a + arguments[i];
			}
			return a;
		}
		var poxyMult = createProxyFactory(mult)
		var poxyAdd = createProxyFactory(add)
		var num = poxyMult(1,2,4,9); // 72
		var num1 = poxyAdd(1,2,4,9); // 17
	</script>
</body>

</html>

改寫後的函數,我們新增一個ADD的計算函數,直接將函數傳入createProxyFactory函數中,就實現了加法的緩存,這樣我們就能實現多種計算的緩存。
這也是實現面向對象的開放封閉原則。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章