python 设计模式之代理模式

在代理设计模式下,提供给客户端使用的是能真实提供服务的对象的替代品,这个替代品被称之为代理,代理收到客户端请求后进行一些处理(访问控制,缓存等),然后将请求透传给服务对象。

代理对象与服务对象有相同的接口,因此客户端在使用时无需识别它们究竟是哪一个。

在上面的这段描述中,提及了3个名词:

  1. 服务对象
  2. 代理对象
  3. 客户端

下面通过一个简单的例子来理解代理模式并将这3个概念与代码里的对象一一对应起来。

1. 一个简单例子理解代理模式

我先定义一个表示门的类

class Door():
    def open_door(self):
        print("打开门")

这个类有一个open_door 方法,负责打开门,接下来,我要为这个门进行升级,为它安装一个门禁,只有刷卡才能打开,我设计并实现一个新的类,ProxyDoor

class ProxyDoor():
    def __init__(self):
        self.real_object = Door()

    def open_door(self):
        print("先刷卡")
        self.real_object.open_door()

ProxyDoor并不是Door的子类,它内部有一个real_object 属性,类型是Door,ProxyDoor类也有一个open_door 方法,与Door里的一模一样,最后一步,实现一个open_the_door函数

def open_the_door():
    door = ProxyDoor()
    door.open_door()

open_the_door()

现在,让我们开始理解代理模式是如何工作的。

  • Door 是服务对象
  • ProxyDoor 是代理对象
  • open_the_door 是客户端

真正实现了开门这个服务的,是Door这个类,但是客户端在使用时,却并没有直接使用Door这个类,而是用了代理对象ProxyDoor。

代理对象对open_door 这个方法做出了限制,必须先刷卡,然后将开门的这个要求提供给了Door,ProxyDoor一边接收客户端的请求,一边对请求做了限制性检查并将请求传递给真正的能够提供服务的Door。因此,在代理对象中,必须维护一个服务对象,就本例而言,在ProxyDoor 对象中比如维护一个real_object 对象。

所谓客户端,你可以理解为,谁使用代理对象,谁就是客户端。

2. 代理模式有什么作用和好处呢

代理模式可以实现松耦合,它让你将核心逻辑与可能附加的功能分离,代码的模块化特性使得维护和扩展主要逻辑功能变得更容易。

在代理模式中,核心功能是由服务对象提供的,这使得你可以专注于核心逻辑,代理对象只是在它的基础之上附加了一些新的功能。

3. 使用子类不可以么

就第一小节中的例子而言,其实我们有别的办法来实现相同的效果,比如增加一个子类

class CardDoor(Door):
    def open_door(self):
        print("先刷卡")
        super(CardDoor, self).open_door()


def open_the_door():
    door = CardDoor()
    door.open_door()

open_the_door()

在子类CardDoor中重写open_door方法就可以了,程序最终的执行结果与代理模式是相同的。

如果你能想到这一层,说明你对面向对象编程已经掌握的非常熟练了。这的确是一个难以回答的问题,这也是很多讲解设计模式的文章刻意回避的问题。

我尝试着来回答一下,增加一个子类,固然可以实现相同的效果,但与代理模式相比较,刷卡这个限制仍然被写在了服务对象里,而代理模式追求的是让服务对象更专一的实现其核心逻辑,由代理对象为服务对象增加额外的功能。

我们不去比较这两种模式哪个更好,而是结合实际情况,决定你追求哪种效果,如果代理模式所提供的附加功能存在不确定性,可能在某一天消失或者变动频繁,或者附加功能与服务对象的核心逻辑联系不紧密,我就倾向于使用代理模式当附加功能出现变化时,我修改代理对象就可以了。

增加子类,侧重的是描述定义一个新的类别,对象,代理模式侧重的是为服务对象提供附加的功能,增加子类时,有可能会增加新的属性,而代理模式不改变服务对象的任何属性和方法,仅仅是在中间代理时做一些访问限制,提供一些附加功能。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案