代理设计模式

代理模式(Proxy Design Pattern)用于在不改变原始类(被代理类)代码的情况下,通过引入代理给原始类提供附加功能。

代理就是真实对象的代表,不对外暴露真实对象。

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式的优缺点

优点

  1. 职责清晰:真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
  2. 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
  3. 高扩展性。

代理的分类

  1. 静态代理
  2. 动态代理

应用场景

  1. 非功能或业务性的需求开发:监控、统计、鉴权、限流、事务、日志等。
  2. 通过一个中介控制,使实际对象的安全性更高。
  3. 为不同服务器上的远程对象提供本地的接口,比如RPC。
  4. 消耗大量内存的对象提供一个轻量级的句柄。

静态代理

代理模式的构成

代理模式主要由三部分构成:

  • 原始类(被代理类)
  • 抽象类(实现跟原始类一样的接口)
  • 代理类(实现抽象类)

使用方式

静态代理主要用于内部系统的开发,静态代理的前提,那就是真实类和代理类要实现同一个接口,静态代理主要的步骤可以总结为:

  1. 代理类和原始类实现同一抽象类接口。
  2. 代理类中添加附加的功能,不影响原始类代码。
  3. 将原始类使用的地方替换为代理类。

我们通过代码的方式实现一下,我们以生活中通过中介租房为案例。

通常情况下,我们要租房,但是因为没有渠道,找不到好的房源或者担心私下交易的安全性问题;而房子出租方也是同样,因为没有渠道,找不到好的租客以及担心私下交易的安全性,这时候通过一个合法的中介来充当媒介就是非常好的办法。

抽象类

房东(原始类)和代理类(中介)都要实现 rent_house 的方法。

class IRentHouse(ABC):
    @abstractmethod
    def rent_house(self):
        """
        出租房屋
        """
        pass

房东(原始类)

class RentHouse(IRentHouse):
    def rent_house(self):
        print("我是房东,要出租房子")

中介(代理类)

在实现租房功能的基础上,增加了检查房子出租合法性,以及收取中介费的附加功能,并不影响原来房东出租房子的方法。

class Proxy(IRentHouse):
    def __init__(self, rent_obj: RentHouse):
        self.real_object = rent_obj

    def check_house(self):
        print("检查房子是否合法")

    def get_pay(self):
        print("获取中介费")

    def rent_house(self):
        """
        实现租房功能的基础上,提供附加功能
        """
        # 检查房子是否合法
        self.check_house()

        # 实现租房功能
        self.real_object.rent_house()

        # 收取中介费
        self.get_pay()

调用

# 直接租房者与房东沟通,可能存在风险
RentHouse().rent_house()

# 通过中介,安全实现租房者租房,房东出租房
rent_obj = RentHouse()
Proxy(rent_obj).rent_house()

动态代理

从静态代理的实现中可以发现,静态代理的缺点显而易见,当真实类的方法越来越多的时候,这样构建的代理类的代码量是非常大的,所以就引进动态代理。

动态代理原理

代理类想要动态的实现知道原始类的所有属性和方法,在 java 中,这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。

而 python 没有直接提供有动态代理的设计模型,但我们可以使用 python 中的特殊方法来实现。

使用方法

通过一个公共代理类包装真实类,请求通过代理类实现,从而实现想要增强的功能。

公共代理类

class DynamicProxy:

    def __init__(self, target):
        self.target = target  # 传入的真实类

    def __getattr__(self, item):
        print("进来了")
        raise ModuleNotFoundError("{}方法或属性不存在".format(item))

    def __getattribute__(self, name):
        target = object.__getattribute__(self, "target")
        attr = object.__getattribute__(target, name)

        def newAttr(*args, **kwargs):  # 包装
            print("前操作")
            res = attr(*args, **kwargs)
            print("后操作")
            return res

        return newAttr
  • target 是传入的真实类,也就是要被代理的类。

  • __getattribute__是 python 中的特殊方法,获取属性和方法时,会触发__getattribute()__方法。

  • __getattr__是 python 中的另一个特殊方法,当__getattribute__获取不到属性或方法时,就会触发 getattr 进行兜底。

通过两个特殊方法的配合,就可以实现将传入的真实类绑定在代理上,并获取真实类是否存在某方法或属性从而实现动态代理。

代码实例:

# 真实类
class RentHouse:
    def rent_house(self, a):
        print(a)
        print("我是房东,要出租房子")

    def check_house(self):
        print("检查一下房子")
        
target = RentHouse()
proxy = DynamicProxy(target)
proxy.rent_house(666)
proxy.rent_house2(666)

# 执行结果
前操作
666
我是房东,要出租房子
后操作
进来了
ModuleNotFoundError: rent_house2方法或属性不存在

总结

代理模式可以在不改动原始类的前提上,附加一些非业务性的功能,比如:监控、统计、鉴权、限流、事务、日志等等,可以将这些功能与业务逻辑解耦,让业务只关注业务,是非常好用的一种结构型设计模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tlqwanttolearnit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值