代理模式
代理模式顾名思义,就是通过一个代理去处理问题,例如黑道头子去买军火,一般都是让自己的头号手下去买,自己不参与实际交易~~
虚拟代理
我们先从常见的图片占位图片代理来说明。
通常情况下,我们加载图片的姿势是这样的。
<!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函数中,就实现了加法的缓存,这样我们就能实现多种计算的缓存。
这也是实现面向对象的开放封闭原则。