代理模式

是一种结构型设计模式。 其中代理控制着对于原对象的访问, 并允许在将请求提交给原对象的前后进行一些处理,从而增强原对象的逻辑处理。

上面的代理者我们一般叫做代理对象或者直接叫做代理-- Proxy,进行逻辑处理的原对象通常被称作服务对象,代理要跟服务对象实现相同的接口,才能让客户端傻傻分不清自己使用的到底是代理还是真正的服务对象,这样一来代理就能在客户端察觉不到的情况下对服务对象的处理逻辑进行增强。

什么叫对处理逻辑进行增强?或者换一种说法,叫对核心功能添加增强功能?举个例子来说,处理客户端查询用户订单信息的 API Handler 就是核心处理逻辑,增强逻辑就是我们需要在查询订单信息之前,验证请求是否是有效用户、记录请求的参数和返回的响应数据等等。

看了上面代理模式的解释,你可能还是觉得有点宽泛,下面咱们写一个简单的代码示例,这个过程中你差不多就会发现:“诶,原来这就是代理模式啊,我之前写代码的时候早就用过了~!” 下面我们一起开下这个例子吧。

假设有一个代表小汽车的 Car 类型

type Car struct{}
Drive()
type Vehicle interface {
    Drive()
}

type Car struct{}

func (c *Car) Drive() {
    fmt.Println("Car is being driven")
}
Drive()Vehicle
CarDrive()
CarAgeCarDrive()Vehicle Drive()
Driver
type Driver struct {
    Age int
}

然后再来一个包装 Driver 和 Vehicle 类型的包装类型。

type CarProxy struct {
    vehicle    Vehicle
    driver *Driver
}

func NewCarProxy(driver *Driver) *CarProxy {
    return &CarProxy{&Car{}, driver}
}
vehicleDrive() 
func (c *CarProxy) Drive() {
    if c.driver.Age >= 16 {
        c.vehicle.Drive()
    } else {
        fmt.Println("Driver too young!")
    }
}

我相信这个编程技巧大家在平时开发中都用过,这个其实就是代理模式。

CarDrive()
func main() {
 car := NewCarProxy(&Driver{12})
 car.Drive() // 输出 Driver too young!
 car2 := NewCarProxy(&Driver{22})
 car2.Drive() // 输出 Car is being driven
}
Drive()

看完例子后,相信大家都理解了写代码时怎么使用代理模式,下面我们从代码走出来,再更清晰的描述下代理模式它的整体结构。

根据上面一开始的描述和后面的代码例子,我们总结出来,参与代理模式的一共有四种角色:客户端、服务接口、服务类和代理类,他们之间的关系用 UML 类图表示如下:

 

VehicleDrive()CarVehicleDrive()CarProxyVehicleVehiclevehicleDriverdriverCarProxyDrive()DriverDrive()main()NewCarProxy()CarProxyCarProxyDriverDrive()CarProxyDriverCarProxyDriverCarDrive()
VehicleCarCarProxymain()CarProxyVehicleCarProxyCar

代理模式延伸

在代理模式中,通过让代理类实现跟服务类相同的接口,从而把代理类伪装成了服务类,客户端请求代理时,代理再把请求委派给其持有的真实服务类,在委派的过程中我们就可以添加增强逻辑。

如果我们把代理类当成服务对象再给代理类加个代理,代理的代理再加代理,那么就变成了另外一种设计模式--装饰器模式啦,其实装饰器模式本身就是代理模式的一个特殊应用