设计模式-代理模式

代理模式定义

代理模式是指当两个对象之间不能直接引用时,需要通过代理对象在这两个对象间起到中介的作用。代理可以代替其本体被实例化,并且使其可被远程访问。它还可以把本体实例化推迟到真正需要的时候,对于实例化比较费时的本体,或者尺寸较大处理起来耗时的类都可以使用代理。
代理模式包含虚拟代理、远程代理和保护代理。

代理类型说明
虚拟代理虚拟代理是指用来代替巨大对象,确保它在需要的时候才被创建。在JavaScript中应用较多。
保护代理保护代理常用于根据客户身份控制对特定方法的访问。在JavaScript中不易实现因为我们无法判断谁访问了某个对象
远程代理在Java中,远程代理负责与远程JVM通信,以实现本地调用者与远程被调用者之间的正常交互。但在JavaScript中更多的是应用于控制对其他语言中的本体的访问。

代理模式应用

跨域代理

在JavaScript中,出于对安全访问因素的考虑,不允许跨域通信。跨域代理是远程代理的一种应用。
第一种代理对象形式是通过img之类的标签通过src属性可以向其他域下的服务器发送请求。不过这类get请求是单向的,不会有数据响应,一般会用于页面的埋点统计。

var imgSend = function (params) {
	var img = new Image();
	img.src = URL + this.args;
	img.style.height = "0px";
	img.style.width = "0px";
	img.style.display = "none";
	doc.body.appendChild(img);
	img.onerror = function () {
		doc.body.removeChild(img);
	};
    img.onload = function () {
        doc.body.removeChild(img);
    };
}

第二种代理对象就是通过JSONP方案来解决问题。

		function jsonpFun(URL,callbackname,callback){
			window[callbackname] = callback;
			var oscript = document.createElement("script");
			oscript.src = URL;
			oscript.type = "text/javascript";
			document.head.appendChild(oscript);
			document.head.removeChild(oscript);
		}
 

图片预加载

在web开发中,图片预加载时直接给img标签设置src属性,如果图片过大或者网络不佳会导致有段时间是空白的,常见的做法是先用一张loading图占位,等图片加载好了再填充到img节点。这个场景就可以通过虚拟代理来实现。
首先,先实现一个创建img并赋值src的普通对象作为本体

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

然后,引入一个代理对象,通过这个代理对象,在图片加载完成之前先展示loading图。

var proxyImg = (function(){
	var img = new Image();
	img.onload = function() {
		createImg.setSrc('xxxx');
	}
	return {
		setSrc:function(src) {
			createImg.setSrc('loading');
			img.src = src;
		}
	}
})();
//使用
proxyImg.setSrc('xxxx');

在这里使用代理类的好处就是避免一个对象承担过多的职责,当发生变化时,有可能会影响其他职责的实现。把图片请求和预加载图片这两个功能隔离在两个对象里面,可以降低耦合性,即使它们各自有变化也不会影响到对方。
同时,上例中我们保持普通本体和代理类接口一致有两个好处:客户可以放心使用代理类只关心能否获取到想要的结果;而且在任何本体的地方都可以替换成代理类。

防抖代理

<body>
<input type="checkbox" id="1"></input>1
<input type="checkbox" id="2"></input>2
<input type="checkbox" id="3"></input>3
<input type="checkbox" id="4"></input>4

<script>
var submit = function(id) {console.log("提交数据,id:" + id);}
var checkbox = document.getElementsByTagName('input');
for(var i = 0;i<checkbox.length;i++) {
	checkbox[i].onclick = function(e) {
		if(e.checked) {submit(this.id);}
	}
}
</script>
</body>

上面实现了一个简单的场景,页面上有多个checkbox,当用户点击checkbox选中的时候会发送以数据到服务端。这段代码存在的问题是,如果短时间内用户多次操作checkbox就会出现繁忙的网络请求影响性能。
如果我们新增一个代理类,这个代理类负责收集一段时间内用户操作然后一次性发送给服务端,这样就可以减轻服务端的压力。

var proxySubmit = (function(){
	//定义一个cache数组收集一段时间内需要提交的ID
	var cache = [],timer;
	return function(id) {
		cache.push(id);
		// 如果定时器存在就返回,保证不会覆盖已启动的定时器
		if(timer) {return;}
		timer = setTimeout(function(){
			submit(cache.join(","));
			clearTimeout(timer);
			timer = null;
			cache.length = 0;
		},2000);
	}
})();

缓存代理

缓存代理可以为开销大的计算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的结果。
以计算乘积为例:

let m = function (n) {
    if (n<=1) {
        return 1;
    } else {
        return n*m(n-1);
    }
}
let sum=(function () {
    let cache={};
    return function sum(n) {
        let result=0;
        for (let i=1;i<=n;i++){
            let r=cache[i];
            if (r) {
                result+=r;
            } else {
                r=m(i);
                cache[i]=r;
                result+=r;
            }
        }
        return result;
    }
})()

分页请求也可以运用代理模式,每次请求新的页码时去服务端请求数据并且缓存数据,这样下次再请求同一个页面时就可以直接使用之前的数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值