现代商业界很流行一种叫代理商的人物,在商业界中代理商又称商务代理,是在其行业管理范围内接受他人委托,为他人促成或缔结交易的一般代理人。很多公司为了迅速占领市场,通常会选用一种叫代理商加盟的商业模式。比如快递公司,很多快递公司都会有代理商网点,发送快递时,会先把快递发到网点,然后网点就会发送到收件人手中。在程序语言中,我们把像这种一个类代表另一个类的功能的设计模式叫做代理模式。
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
主要解决问题:在直接访问对象时带来的问题,比如说:比如对象创建开销很大、或者某些操作需要安全控制,直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层(即中间层)。
我们先用一个快递公司发送快递的情形,抽象出来的程序例子,来理解代理模式:
//快递公司 var ExpressCompany = { name: "某某快递公司", send: function(target){ ProxyBranch.receive(target, this.name); } }; //快递公司代理网点 var ProxyBranch = { receive: function(target, company){ target.receive(company); } }; //快递收件人 var Receiver = { name: '小明', receive:function(company){ console.log(this.name + "接收到了" + company + "发来的快递。"); } }; //快递公司发送快递给收件人 ExpressCompany.send(Receiver);
这段代码里,代理网点(即ProxyBranch类)代替收件人小明(即Receiver类)从快递公司(即ExpressCompany类)接收过快递,然后,代理网点(即ProxyBranch类)再将快递发送到收件人小明(即Receiver类)手里。
保护代理
通过上面的代码实例,我们了解到了什么是代理模式,但上面的代理模式可以说是没有任何意义的,而且还无端增加了程序的复杂性。现实中小明有可能天天,无时无刻都在家吗?这是不可能的。那么代理网点的工作人员是不是要等到小明在家的时候才能把快递送到小明的手里,这是肯定的。这样的话,是不是相当于小明被设置了访问权限,只有他在家的时候才能访问。这就是保护代理,控制其他程序对被代理对象的访问。
现在我们用保护代理改写上面的程序:
//快递公司 var ExpressCompany = { name: "某某快递公司", send: function(target){ ProxyBranch.receive(target, this.name); } }; //快递公司代理网点 var ProxyBranch = { receive: function(target, company){ var time = target.time, h = new Date().getHours(); for(var i = 0, l = time.length; i < l; i++){ if(time[i][0] < h < time[i][1]){ target.receive(company); break; } } } }; //快递收件人 var Receiver = { name: '小明', time: [ //小明空闲在家的时间段,他还开启了夜间免打扰模式 [7, 9], [12, 14], [17, 20] ], receive:function(company){ console.log(this.name + "接收到了" + company + "发来的快递。"); } }; //快递公司发送快递给收件人 ExpressCompany.send(Receiver);
虚拟代理
在上面讲述保护代理的代码片段中,小明是从一开始就被创建的一个接受者,这就好比代理网点一直都在惦记着小明有没有要接收的快递,这是完全没有必要的,网点只需在从快递公司接收到小明的快递时再想起小明就可以了。也就是说,在一开始就把小明这个接受者创建出来是非常的耗费系统资源的,我们应该换一种方式,在ProxyBranch类执行receive()方法时再创建小明这个Receiver对象的实例。像这样的代理方式叫虚拟代理,虚拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建。
看下面的程序实例,理解什么是虚拟代理:
//快递公司 var ExpressCompany = { name: "某某快递公司", send: function(target){ ProxyBranch.receive(target, this.name); } }; //快递公司代理网点 var ProxyBranch = { receive: function(target, company){ var person = new Receiver(target); person.receive(company); } }; //快递收件人 var Receiver = function(name){ this.name = name; this.receive = function(company){ var message = this.name + "接收到了" + company + "发来的快递。"; console.log(message); } }; //快递公司发送快递给收件人 ExpressCompany.send("小明");
代理模式的优缺点:
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。