1

什么是代理模式

代理模式,类似于明星的经纪人,想要拜访明星,需要先通过经纪人的沟通。而在JS当中,如果想访问一个类,需要通过另一个类来间接访问 。不同于装饰器,那种动态加载一个对象,可以说在代理模式当中,代理是早已既定的。

别人眼中的代理

这里写图片描述
再拿最常遇到的收快递这一个社会行为举例吧。
很早之前,我们收发快递都是直接和快递员交互的,例如:
这里写图片描述
而现在,加入了代理之后,可以通过第三方替我们接收快递,即:
这里写图片描述
这是生活当中一个非常常见的例子,可以说代理的存在,大大的便利了“我”这个对象。下面就让我们在程序中看看代理是如何方便“我”的。

程序中的代理

程序做这样一件事,即根据不同的快递类型,来进行不同的操作(执行不同的函数),那么在没有引进代理之前,写法可能是这个样子。
无代理:

class getDelivery {
    constructor() {

    }

    gets(a) {
         let fn1 = () => {
                setTimeout(() => {
                    //some fns of fn1
                   console.log(`获取快递有:${a}`)
                }, 1000)
        }
        let fn2 = () => {
                setTimeout(() => {
                    //some fns of fn2
                    console.log(`获取快递有:${a}`)
                }, 2000)
        }
        let fn3 = () => {
                setTimeout(() => {
                    //some fns of fn3
                   console.log(`获取快递有:${a}`)
                }, 3000)
        }
        let deliver = {'中通': fn1, 'EMS': fn2, '顺丰': fn3}[name];
        return deliver();
    }
}
getDelivery.prototype.proxyGets('中通') 

定义一个类,上面的gets函数去判断不同的快递类型,然后去执行相对应的操作。

现在,当我们引入代理模式之后,代码可能是这样的:
代理:

class getDelivery {
    constructor() {

    }

    gets(a) {
        console.log(`获取快递有:${a}`)
    }
}


class proxy extends getDelivery {
    constructor() {
        super();
    }

    proxyGets(name) {
        let fn1 = () => {
                setTimeout(() => {
                    //some fns of fn1
                    super.gets('中通快递')
                }, 1000)
        }
        let fn2 = () => {
                setTimeout(() => {
                    //some fns of fn2
                    super.gets('EMS')
                }, 2000)
        }
        let fn3 = () => {
                setTimeout(() => {
                    //some fns of fn3
                    super.gets('顺丰')
                }, 3000)
        }
        let deliver = {'中通': fn1, 'EMS': fn2, '顺丰': fn3}[name];
        return deliver();
    }
}

proxy.prototype.proxyGets('中通')

(ps:本代码仅用于代理模式的示例,每次调用函数重新声明fn1等方法是不对的)
ok,这两种方法都会得到这样的结果:
这里写图片描述
而后者在代码上还多了一些,但为什么这里还是推荐使用后面这种模式来写代码呢?

使用代理模式的好处

首先介绍一个面向对象设计原则,单一职责原则

又称单一功能原则,面向对象五个基本原则(SOLID)之一。它规定一个类应该只有一个发生变化的原因。所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。

而在本例中,我们并不关心是什么快递,关心的只是接到快递触发的结果,或者说接到快递后,执行的任务才是getDelivery 这个类的核心,至于中间的过程,应该交给专门处理他的类来判别。

第二个原则:开放封闭原则

开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是对这一目标的最直接体现。其他的设计原则,很多时候是为实现这一目标服务的,例如以Liskov替换原则实现最佳的、正确的继承层次,就能保证不会违反开放封闭原则。

还以接收快递为例,比如有一天,接收快递的形势变了,或者说,根本不需要判断是什么快递,可以随时接收,那么proxy 这个类其实就没有用了,此时我们可以直接调用getDelivery这个类。但是,如果以第一种写法的话,那就是无路可退了,只能去原对象中去删掉相对应的逻辑。当代码复杂程度变高的话,高耦合的程序,会让人非常恶心。

代理模式,在实践当中还可以应用于缓存ajax异步数据,惰性加载等等方面,本文不详细讲解,仅作抛砖引玉的入门参考。


j_bleach
2.5k 声望70 粉丝

1 >> 1