代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。javascript
保护代理:当有许多需求要向某对象发出一些请求时,能够设置保护代理,经过一些条件判断对请求进行过滤。java
虚拟代理:在程序中能够能有一些代价昂贵的操做。此时能够设置虚拟代理去代为执行,这里的虚拟代理便会在适合的时候(须要用到的时候)才去执行。设计模式
保护代理用于控制不一样权限的对象对目标对象的访问,但在JavaScript并不容易实现保护代理,由于咱们没法判断谁访问了某个对象。而虚拟代理是最经常使用的一种代理模式。缓存
预加载图片在Web开发中十分经常使用,其经过异步的方式加载图片,利用一张loading图片占位。等图片加载好以后把图片填充到img节点中。app
var myImage = (function(){
var imgNode = document.createElement('img')
document.body.appendChild(imgNode)
return {
setSrc: function(src){
imgNode.src = src
}
}
})()
var proxyImage = (function(){
var img = new Image()
img.onload = function(){
myImage.setSrc(this.src)
}
return {
setSrc: function(src){
myImage.setSrc('loading.gif')
img.src = src
}
}
})()
proxyImage.setSrc('realImage.jpg')
复制代码
经过
proxyImage
间接的访问了MyImage
。proxyImage
控制了客户对MyImage
的访问,而且在此过程当中加入了一些额外的操做,好比在真正的图片加载好以前,先把img节点的src设置为一张loading图片。异步
面向对象设计原则——单一职责原则。单一职责原则指的是,就一个类(一般也包括对象和函数等)而言,应该仅有一个引发它变化的缘由。若是一个对象承担了多项职责,就意味着这个对象将变得巨大,引发它变化的缘由会有多个。面向对象设计鼓励将行为分布到细粒度的对象之中,若是一个对象承担的职责过多,等于把这些职责耦合到了一块儿,这种耦合会致使脆弱和低内聚的设计,带变化发生时,设计可能会遭到意外的破坏。函数
虚拟代理例子中,代理模式给系统添加了额外的功能,预加载图片。而咱们实际须要的只是MyImage
的setImage
方法。预加载只是一个锦上添花的功能。经过代理模式使得这两个功能独立开来,遵循了开放-封闭原则。ui
缓存代理能够为一些开销大的运算结果提供暂时的存储,在下次运算时,若是传递进来的参数跟以前一致,则能够直接返回前面存储的运算结果。this
乘积运算的例子spa
/*******计算乘积******/
var mult = function(){
console.log('开始计算乘积')
var a = 1
for (var i = 0,l = arguments.length;i<l;i++){
a = a*arguments[i]
}
return a
}
/********乘积代理函数********/
var proxyMult = (function(){
var cache = {} // 缓存对象
return function(){
var args = Array.prototype.join.call(arguments,',') // 将参数转化成字符串做为cache的key
if (args in cache){
// 若是cache对象中存储了一样的参数,直接返回对应的运算结果
console.log('缓存结果:')
return cache[args]
}
// 若是没有该运算参数,保存新的参数和结果,并调用mult方法返回运算结果。
return cache[args] = mult.apply(this, arguments)
}
})()
console.clear()
console.log(proxyMult(1,2,3,4,5)) // mult运算
console.log(proxyMult(1,2,3,4,5)) // 读取缓存结果
console.log(proxyMult(1,2,3,4)) // mult运算
console.log(proxyMult(1,2,3,4)) // 读取缓存结果
/*******建立缓存代理的工厂函数*******/
var createProxyFactory = function(fn){
var cache = {}
return function(){
var args = Array.prototype.join.call(arguments,',')
if(args in cache){
return cache[args]
}
return cache[args] = fn.apply(this, arguments)
}
}
var proxyMult = createProxyFactory(mult)
console.log(proxyMult(12,3,4,5,6))
console.log(proxyMult(12,3,4,5,6))
复制代码
虽然代理模式很是有用,但咱们在编写业务代码的时候,每每不须要去预先猜想是否须要使用代理模式。当真正发现不方便直接访问某个对象的时候,再编写代理不迟。
代理模式是一种很实用的设计模式,很好的诠释了面向对象中的单一职责原则和开放-封闭原则。在实际开发的时候每每会迫于进度压力或者实现了再说的态度忽略了一些必要的代码的可维护性,我以为在一些简单的地方去试着遵循一些设计理念是对本身代码能力的提高。固然不要为了设计而设计啦。
Done is better then Perfect
原文出自 Roy's Blog
《JavaScript设计模式与开发实践》—— 曾探