设计模式-代理模式

代理模式

什么是代理模式?

代理模式是一种结构型设计模式,它允许你提供一个实际对象的替代品或占位符。代理控制着对原对象的访问,并允许在将请求提交给原对象之前或之后执行某些操作。

简单来说,就像现实生活中的"中介"或"代理人"。比如:

  • 你想买火车票,不去火车站(原对象),而是去代售点(代理)。

  • 明星(原对象)通常有经纪人(代理)来处理事务。

  • 你想访问一个国外的网站(原对象),可能需要通过一个代理服务器(代理)。

代理模式的核心思想:

客户端并不直接与实际服务的对象打交道,而是通过一个代理对象。这个代理对象看起来和实际服务的对象一样(通常实现相同的接口),但它内部会控制对实际对象的访问。

代理模式的参与者:

  1. Subject (抽象主题角色):

    • 定义了真实主题和代理主题的共同接口。

    • 这样,在任何使用真实主题的地方都可以使用代理主题。

    • 通常是一个接口或抽象类。

  2. RealSubject (真实主题角色):

    • 定义了代理所代表的真实对象。

    • 是真正执行业务逻辑的类。

  3. Proxy (代理主题角色):

    • 包含对真实主题的引用(聚合关系)。

    • 它实现了抽象主题接口,所以可以替代真实主题。

    • 代理角色负责在请求传递给真实主题之前或之后执行额外的操作,或者自己处理一些请求而不传递给真实主题。

  4. Client (客户端):

    • 通过抽象主题接口与代理对象交互。

    • 客户端通常不知道它是在与代理对象还是真实对象交互。

图示(简化版):

复制代码
+-----------+       uses       +-----------+
|  Client   |--------------->|  Subject  |
+-----------+                  (Interface) +-----------+
                                   ^
                                   | (implements)
                       +-----------+-----------+
                       |                       |
               +-----------+           +-------------+
               |   Proxy   |---------->| RealSubject |
               +-----------+  (holds a  +-------------+
(controls access to)  reference)

为什么使用代理模式?(优点)

  1. 控制访问: 代理可以控制对真实对象的访问权限,例如进行身份验证或权限检查。

  2. 增加额外功能: 可以在不修改真实对象代码的情况下,为真实对象添加额外的功能,如日志记录、缓存、事务管理等。这符合开闭原则。

  3. 延迟加载 (Lazy Initialization) / 虚拟代理: 如果真实对象的创建或加载非常耗时,代理可以在真正需要时才创建或加载它,从而提高应用启动速度和性能。

  4. 远程代理: 代理可以代表一个位于远程地址空间的对象,对客户端隐藏网络通信的复杂性。

  5. 智能引用: 当真实对象被访问时,代理可以执行一些附加操作,如计算真实对象的引用次数,当没有引用时,可以自动释放它。

常见的代理模式类型:

  1. 远程代理 (Remote Proxy):

    • 为一个位于不同地址空间的对象提供一个本地的代表。

    • 例如,Java RMI 中的 Stub 对象就是客户端的远程代理。客户端调用 Stub 的方法,Stub 负责网络通信,将请求转发给服务器端的真实对象。

  2. 虚拟代理 (Virtual Proxy):

    • 根据需要创建开销很大的对象。

    • 例如,一个图片查看器程序,可以先显示一个占位符(虚拟代理),当用户真正要查看大图时,才加载真实的图片对象。

  3. 保护代理 (Protection Proxy):

    • 控制对原始对象的访问。

    • 用于对象应该具有不同访问权限的情况。例如,根据用户角色决定是否允许执行某个操作。

  4. 智能引用代理 (Smart Reference Proxy):

    • 当对象被引用时,提供一些额外的操作,例如:

      • 记录对象的引用次数。

      • 在第一次引用一个持久对象时,将它装入内存。

      • 在访问一个实际对象前,检查是否已经锁上了它,以确保其他对象不能改变它。

  5. 缓存代理 (Caching Proxy):

    • 为开销大的运算结果提供暂时存储。它可以允许多个客户端共享结果,以减少计算或网络延迟。

    • 例如,网页代理服务器缓存常访问的网页。

一个简单的虚拟代理例子 (Python 伪代码):

复制代码
from abc import ABC, abstractmethod
​
# 1. Subject (抽象主题)
class Image(ABC):
    @abstractmethod
    def display(self):
        pass
​
# 2. RealSubject (真实主题)
class RealImage(Image):
    def __init__(self, filename: str):
        self._filename = filename
        self._load_from_disk() # 模拟耗时操作
​
    def _load_from_disk(self):
        print(f"Loading image: {self._filename} from disk...")
        # 模拟加载时间
        import time
        time.sleep(2)
​
    def display(self):
        print(f"Displaying image: {self._filename}")
​
# 3. Proxy (代理主题) - 虚拟代理
class ProxyImage(Image):
    def __init__(self, filename: str):
        self._filename = filename
        self._real_image: RealImage = None # 真实对象引用,初始为None
​
    def display(self):
        if self._real_image is None: # 延迟加载
            print("Proxy: RealImage not loaded yet. Creating it now.")
            self._real_image = RealImage(self._filename)
        self._real_image.display()
​
# 4. Client (客户端)
if __name__ == "__main__":
    print("Creating proxy image objects (not loading yet)...")
    image1 = ProxyImage("photo1.jpg")
    image2 = ProxyImage("photo2.png")
​
    print("\nClient: Requesting to display image1 for the first time:")
    image1.display() # 此时会加载 RealImage
​
    print("\nClient: Requesting to display image1 again:")
    image1.display() # 此时直接使用已加载的 RealImage
​
    print("\nClient: Requesting to display image2 for the first time:")
    image2.display() # 此时会加载 RealImage

缺点:

  • 增加类的数量: 引入代理对象,可能会导致系统中的类数量增加。

  • 增加一层间接性: 由于在客户端和真实主题之间增加了代理对象,会引入一定的间接性,可能会造成请求处理速度变慢(虽然通常这种影响很小,且常常被代理带来的好处所抵消)。

总结:

代理模式是一种非常实用和灵活的设计模式,它通过引入一个代理对象来间接访问目标对象,从而可以在不改变目标对象代码的前提下,增加额外的控制和功能。选择哪种类型的代理取决于具体的需求场景。

相关推荐
琢磨先生David6 小时前
责任链模式:构建灵活可扩展的请求处理体系(Java 实现详解)
java·设计模式·责任链模式
charlie1145141918 小时前
从C++编程入手设计模式1——单例模式
c++·单例模式·设计模式·架构·线程安全
琢磨先生David9 小时前
Java 访问者模式深度重构:从静态类型到动态行为的响应式设计实践
java·设计模式·访问者模式
米粉030511 小时前
代理模式核心概念
代理模式
pengles11 小时前
Spring AI 代理模式(Agent Agentic Patterns)
人工智能·spring·代理模式
linux-hzh17 小时前
设计模式之原型模式
设计模式·原型模式
蔡蓝18 小时前
设计模式-工厂方法模式
java·设计模式·工厂方法模式
linux-hzh18 小时前
设计模式之单例模式
单例模式·设计模式
_abab18 小时前
Nginx 基本概念深度解析:从服务器特性到代理模式应用
服务器·nginx·代理模式
QQ_hoverer19 小时前
Java设计模式之工厂模式与策略模式简单案例学习
java·开发语言·学习·设计模式·策略模式