万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • 数据结构与算法

  • 设计模式

    • 23种设计模式

      • 设计模式概述
      • 监听模式
      • 状态模式
      • 中介模式
      • 装饰模式
      • 单例模式
      • 原型模式
      • 职责模式
      • 代理模式
        • 什么是代理模式
        • 代理模式的设计思想
        • 从生活中领悟代理模式
        • 代理模式的框架模型
        • 应用场景
      • 外观/门面模式
      • 迭代模式
      • 组合模式
      • 构建模式
      • 适配器模式
      • 策略模式
      • 工厂模式
      • 命令模式
      • 备忘模式
      • 享元模式
      • 访问模式
      • 模板模式
      • 桥接模式
      • 解释模式
    • 设计模式拓展

    • 设计原则

  • 编程方法论

  • 分布式设计与微服务理论

  • Leetcode

  • 程序员内功
  • 设计模式
  • 23种设计模式
2021-07-01
目录

代理模式

# 代理模式

# 什么是代理模式

Provide a surrogate or placeholder for another object to control access to it.

为其他对象提供一种代理来控制对它的访问。简单来说就是,一个对象可能拥有一个或多个对象的引用,该对象就称为他们的代理,代理对象可以操作这些被代理对象,调用被代理对象的方法来处理外界的请求。

# 代理模式的设计思想

代理模式(Proxy)的核心思想:

  • 使用一个额外的间接层来支持分散的、可控的、智能的访问。
  • 增加一个包装和委托来保护真实的组件,以避免过度复杂。

简单阐述:代理对象可以在客户端和目标对象之间起到中间调和的作用,并且可以通过代理对象隐藏不希望被客户端看到的内容和服务,或者添加客户需要的额外服务。

# 从生活中领悟代理模式

在现实生活中有非常多的代理模式的模型:代拿快递、火车票机票代售点、公司代表出席会议。

这里使用代拿快递做例子:Tony的快递(雪地靴)到了,但是由于不在家,让邻居 Wendy 代拿快递。

# 代理模式-代收快递
from abc import ABCMeta, abstractmethod


class ReceiveParcel(metaclass=ABCMeta):
    """接收包裹抽象类"""

    def __init__(self, name):
        self.__name = name

    def getName(self):
        return self.__name

    @abstractmethod
    def receive(self, parcelContent):
        pass


class TonyReception(ReceiveParcel):
    """Tony 接收"""

    def __init__(self, name, phoneNum):
        super().__init__(name)
        self.__phoneNum = phoneNum

    def getPhoneNum(self):
        return self.__phoneNum

    def receive(self, parcelContent):
        print("货物主人:%s, 手机号:%s" % (self.getName(), self.getPhoneNum()))
        print("接受到一个包裹, 包裹内容:%s" % parcelContent)


class WendyReception(ReceiveParcel):
    """Wendy 代收"""

    def __init__(self, name, receiver):
        super().__init__(name)
        self.__receiver = receiver

    def receive(self, parcelContent):
        print("我是%s的朋友,我来帮他代收快递 " % (self.__receiver.getName()+""))
        if(self.__receiver is not None):
            self.__receiver.receive(parcelContent)
        print("代收人:%s" % self.getName())


def testReceiveParcel():
    tony = TonyReception("Tony", "18812345678")
    print("Tony 接收:")
    tony.receive("雪地靴")
    print()

    print("Wendy 代收:")
    wendy = WendyReception("Wendy", tony)
    wendy.receive("雪地靴")


if __name__ == "__main__":
    testReceiveParcel()

"""
Tony 接收:
货物主人:Tony, 手机号:18812345678
接受到一个包裹, 包裹内容:雪地靴

Wendy 代收:
我是Tony的朋友,我来帮他代收快递 
货物主人:Tony, 手机号:18812345678
接受到一个包裹, 包裹内容:雪地靴
代收人:Wendy

Process finished with exit code 0
"""

ReceiveParcel:接收包裹动作的抽象类,receive方法需要每个子类去实现接收包裹的动作实现。

TonyReception是被代理类,WendyReception是代理类,代理类会引用被代理类,调用被代理类的receive方法,去接收包裹。

# 代理模式的框架模型

对示例代码进一步重构和优化,抽象代理模式框架

# 类图和实现

代理模式框架

Subject:活动主题(代理行为)的抽象基类,负责定义统一的接口。例如接收快递、代购、参会代表等。抽象出来的行为使用request表示。

RealSubject:真实主题(被代理对象)真正去处理主题的对象,是Subject的具体实现类。

ProxySubject:代理主题(代理对象),代理RealSubject的功能,同样是Subject的具体实现类,但是往往比RealSubject要复杂些。

框架代码:

# 代理模式 框架
from abc import ABCMeta, abstractmethod


class Subject(metaclass=ABCMeta):
    """主题类"""

    def __init__(self, name):
        self.__name = name

    def getName(self):
        return self.__name

    @abstractmethod
    def request(self, content = ''):
        pass


class RealSubject(Subject):
    """真实主题类"""

    def request(self, content):
        print("RealSubject todo something...")


class ProxySubject(Subject):
    """代理主题类"""

    def __init__(self, name, subject):
        super().__init__(name)
        self._realSubject = subject

    def request(self, content = ''):
        self.preRequest()
        if(self._realSubject is not None):
            self._realSubject.request(content)
        self.afterRequest()

    def preRequest(self):
        print("preRequest")

    def afterRequest(self):
        print("afterRequest")


def testProxy():
    realObj = RealSubject('RealSubject')
    proxyObj = ProxySubject('ProxySubject', realObj)
    proxyObj.request()


if __name__ == "__main__":
    testProxy()

"""
preRequest
RealSubject todo something...
afterRequest
"""

示例代码基于框架实现,会简单很多,仅仅调用方法 由 receive 变成了 request :

# 代理模式2.0 - 基于框架框架代收快递
from proxy_frame import Subject, ProxySubject


class TonyReception(Subject):
    """Tony 接收"""

    def __init__(self, name, phoneNum):
        super().__init__(name)
        self.__phoneNum = phoneNum

    def getPhoneNum(self):
        return self.__phoneNum

    def request(self, content = ''):
        print("货物主人:%s, 手机号:%s" % (self.getName(), self.getPhoneNum()))
        print("接受到一个包裹, 包裹内容:%s" % str(content))


class WendyReception(ProxySubject):
    """Wendy 代收"""

    def __init__(self, name, receiver):
        super().__init__(name, receiver)

    def preRequest(self):
        print("我是%s的朋友,我来帮他代收快递 " % (self._realSubject.getName() + ""))

    def afterRequest(self):
        print("代收人:%s" % self.getName())


def testReceiveParcel():
    tony = TonyReception("Tony", "18812345678")
    print("Tony 接收:")
    tony.request("雪地靴")
    print()

    print("Wendy 代收:")
    wendy = WendyReception("Wendy", tony)
    wendy.request("雪地靴")


if __name__ == "__main__":
    testReceiveParcel()

"""
Tony 接收:
货物主人:Tony, 手机号:18812345678
接受到一个包裹, 包裹内容:雪地靴

Wendy 代收:
我是Tony的朋友,我来帮他代收快递 
货物主人:Tony, 手机号:18812345678
接受到一个包裹, 包裹内容:雪地靴
代收人:Wendy
"""

# 设计要点

区分代理模式的三个角色:

  1. 主题(Subject,被代理的行为):定义操作、活动、任务的接口类。
  2. 真实主题(RealSubject,被代理类):真正完成操作、活动、任务的具体类。
  3. 代理主题(ProxySubject,代理类):代替真实主题,完成操作、活动、任务的代理类。

# 代理模式优缺点

优点:

  • 代理模式能够协调调用者和被调用者,在一定程度上降低系统的耦合度。
  • 可以灵活地隐藏被代理对象的部分功能和服务,也可以增加额外的功能和服务。

缺点:

  • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
  • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

# 应用场景

  1. 不想或者不能直接引用一个对象时。

    • 在移动端加载网页信息时,因为下载真实大图比较耗费流量、影响性能,可以用一个小图代替渲染(用一个代理对象去下载小图),在真正点击图片时,才去下载大图,显示大图效果。

    • HTML中占位符也是代理模式思想。

  2. 想对一个对象的功能进行加强时。

    • 在字体渲染时,遇到粗体渲染的时候,可使用字体对象进行代理,只要在对字体进行渲染后进行加粗的操作即可。
  3. 各种特俗用途的代理:远程代理、虚拟代理、Copy-on-Write代理、保护(ProtectorAccess)代理、Cache代理、防火墙(Firewall)代理、同步化(Synchronization)代理、智能引用(SmartReference)代理。

摘自: 罗伟富. 《人人都懂设计模式:从生活中领悟设计模式:Python实现》. 电子工业出版社

#23种设计模式
上次更新: 5/21/2023, 11:34:33 PM
外观/门面模式

外观/门面模式→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式