代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问
js中常用的两个代理
- 虚拟代理
假设现实中的花价格不菲,导致在程序世界里,new Flower 也是一个代价昂贵的操作,那么我们可以把 new Flower 的操作交给代理 B 去执行,代理 B 会选择在 A 心情好时再执行 new Flower,这是代理模式的另一种形式,叫作虚拟代理。 - 缓存代理
这里主要是通过一个代理来存储方法执行的缓存信息,提高方法的运行效率。
代理和面向对象设计的关系
涉及的两个原则
- 单一职责原则
单一职责原则指的是,就一个类(通常也包括对象和函数等)而言,应该仅有一个引起它变化的原因。 - 开放-封闭原则
开放-封闭原则指的是,软件应该面向拓展开放, 而面向修改封闭。也就是我们在新增功能的时候应该增加代码,而不是修改代码。
在面向对象的程序设计中,大多数情况下,若违反其他任何原则,同时将违反开放—封闭原则。
通过代理模式,在进行对象的编写时,我们可以有一种方式来遵循以上两个原则。
- 我们可以将核心功能抽离为一个对象,一般而言,核心功能是不会变化的,保证封闭原则。
- 将其它拓展功能作为代理进行实现,这样可以在不改动核心功能的前提下对我们的功能进行拓展,而在需要移除某些功能时也可以直接在代理上进行操作。保证开放原则。
实现
Java 等语言中,代理和本体都需要显式地实现同一个接口,一方面接口保证了它们会拥有同样的方法,另一方面,面向接口编程迎合依赖倒置原则,通过接口进行向上转型,从而避开编译器的类型检查,代理和本体将来可以被替换使用。
使用高阶函数创建缓存代理
//这里实现的是 cache proxy
const muti = (...arguments) =>{
return arguments.reduce( (pre, cur) => pre * cur);
}
const plus = (...arguments) => {
return arguments.reduce( ( pre, cur) => pre + cur) ;
}
/**
*
* @param computionalFunction
*
* @returns a proxy for computional function with cache
*
* */
const createCacheProxy = function ( fn ) {
let cache = {};
return function (){
let args = Array.prototype.join.call( arguments, ','); // same as hash
if( args in cache )
{
return cache[args];
}
return cache[ args ] = fn.apply(this, arguments);
}
}
let cachedMuti = new createCacheProxy(muti);
console.log(cachedMuti(1,2,3,4));
在 JavaScript 开发中最常用的是虚拟代理和缓存代理。虽然代理模式非常有用,但我们在编写业务代码的时候,往往不需要去预先猜测是否需要使用代理模式。当真正发现不方便直接访问某个对象的时候,再编写代理也不迟。