设计模式教程:代理模式(Proxy Pattern)

代理模式(Proxy Pattern)是一种结构型设计模式,它通过创建一个代理对象来控制对另一个对象的访问。代理对象充当真实对象的替代者,并且可以在访问真实对象之前或者之后执行额外的操作。代理模式常用于延迟加载、权限控制、远程代理、缓存等场景。

1. 代理模式的定义

代理模式 通过引入代理对象来控制对某个对象的访问。代理对象和真实对象实现相同的接口,客户端对代理对象的操作就像是对真实对象的操作一样,但代理对象可以在操作前或操作后做一些额外的处理。

代理模式通常用于以下几种场景:

  • 远程代理:表示一个对象在不同的地址空间(通常是网络)上的代理。
  • 虚拟代理:用于延迟初始化的场景,只有在需要时才创建对象。
  • 保护代理:控制对对象的访问权限,做权限检查。
  • 缓存代理:缓存某个对象的状态,避免重复计算。

2. 代理模式的角色

代理模式主要涉及以下几个角色:

  • Subject(抽象主题角色):定义了真实对象和代理对象的公共接口,通常是一个接口或抽象类。真实对象和代理对象都要实现这个接口。

  • RealSubject(真实主题角色) :实现了 Subject 接口,定义了代理所代表的真实对象的具体业务逻辑。

  • Proxy(代理角色) :代理对象也实现了 Subject 接口,内部持有对真实对象的引用。代理对象可以在调用真实对象方法之前或之后执行一些额外操作。

3. 代理模式的种类

根据代理的使用场景,代理模式可以分为以下几种类型:

1) 虚拟代理(Virtual Proxy)

虚拟代理用于延迟加载对象。它会在客户端首次请求真实对象时才创建真实对象实例,并返回给客户端。虚拟代理通常用于大对象、资源消耗大的对象的加载。

2) 远程代理(Remote Proxy)

远程代理用于对象位于不同地址空间的情况(如跨网络访问)。它代表一个远程对象,通过代理对象来实现对远程对象的访问。常见的应用场景是分布式系统中的远程调用(如 RMI)。

3) 保护代理(Protection Proxy)

保护代理控制对某个对象的访问权限。它通常会在客户端访问真实对象之前,进行权限验证、日志记录等操作,确保只有合法的操作才会传递到真实对象。

4) 缓存代理(Cache Proxy)

缓存代理用于缓存真实对象的计算结果,避免重复的计算。当请求真实对象时,代理对象先检查缓存,如果存在则直接返回缓存中的结果;如果不存在,则请求真实对象并将结果缓存。

5) 智能代理(Smart Proxy)

智能代理对真实对象的访问进行了额外的处理,通常用来实现一些辅助功能,如计数、对象生命周期管理等。

4. 代理模式的结构图

Matlab 复制代码
 +---------------------+
 |       Subject       |<-----------------------+
 +---------------------+                        |
 | + request()         |                        |
 +---------------------+                        |
         ^                                     |
         |                                     |
 +------------------------+                   |
 |   RealSubject          |                   |
 +------------------------+                   |
 | + request()            |                   |
 +------------------------+                   |
         ^                                     |
         |                                     |
 +------------------------+                   |
 | Proxy                  |-------------------+
 +------------------------+
 | + request()            |
 +------------------------+

5. 代理模式的实现

代码示例:代理模式用于控制访问权限

假设我们有一个 RealSubject 类,它表示一个资源管理对象。我们希望控制对该资源的访问,只有合法用户才能访问资源。为此,我们可以使用代理模式,通过一个代理类来控制访问。

代码实现:
java 复制代码
// 主题接口(Subject)
interface Subject {
    void request();
}

// 真实主题类(RealSubject)
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request");
    }
}

// 代理类(Proxy)
class Proxy implements Subject {
    private RealSubject realSubject;
    private String userRole;

    public Proxy(String userRole) {
        this.userRole = userRole;
    }

    @Override
    public void request() {
        if (checkAccess()) {
            if (realSubject == null) {
                realSubject = new RealSubject();  // 延迟加载
            }
            realSubject.request();  // 代理请求转发给真实主题对象
        } else {
            System.out.println("Proxy: Access denied.");
        }
    }

    // 检查用户权限
    private boolean checkAccess() {
        if ("admin".equals(userRole)) {
            System.out.println("Proxy: Access granted.");
            return true;
        } else {
            System.out.println("Proxy: Access denied.");
            return false;
        }
    }
}

public class ProxyPatternExample {
    public static void main(String[] args) {
        // 创建代理对象并检查访问权限
        Subject proxy = new Proxy("admin");  // 用户为 admin,访问权限允许
        proxy.request();

        System.out.println();

        Subject proxy2 = new Proxy("user");  // 用户为普通用户,访问权限被拒绝
        proxy2.request();
    }
}
代码解析:
  1. Subject :定义了 request() 方法,RealSubjectProxy 都实现了该接口。
  2. RealSubject :实现了 Subject 接口的具体业务逻辑,执行实际的请求处理。
  3. Proxy :是代理类,它控制对 RealSubject 的访问,首先检查是否具有访问权限(在本例中是通过 userRole 字段来判断),如果允许访问,则代理请求转发给 RealSubject;否则拒绝访问。
  4. 检查访问权限Proxy 类中的 checkAccess() 方法根据用户角色来判断是否允许访问。如果角色是 admin,则允许访问;否则拒绝访问。
输出:
Matlab 复制代码
Proxy: Access granted.
RealSubject: Handling request

Proxy: Access denied.

在这个例子中,代理模式通过 Proxy 类来控制访问,只有用户角色为 admin 时才能访问 RealSubject。这种方式实现了对真实对象的访问控制和延迟加载。

6. 代理模式的应用场景

代理模式可以应用于以下场景:

  1. 延迟加载(虚拟代理): 当对象的创建开销非常大,且客户端并不总是需要该对象时,可以使用虚拟代理延迟创建该对象。只有在客户端真正需要时,才创建真实对象。

  2. 权限控制(保护代理): 在某些系统中,可能希望对访问某些资源进行权限控制。通过代理模式,可以在请求到达真实对象之前,对请求进行权限检查。

  3. 缓存管理(缓存代理): 如果某些对象的计算非常耗时或结果不会经常改变,可以使用缓存代理来缓存对象的计算结果。当再次请求时,直接从缓存中获取数据,避免重复计算。

  4. 远程代理: 远程代理可以让客户端像操作本地对象一样操作远程对象。例如,远程过程调用(RPC)就是通过代理模式实现的,客户端调用远程服务器上的方法时,代理对象会负责实际的远程调用。

  5. 日志记录(智能代理): 通过代理模式,在对真实对象的操作前后可以插入日志记录、性能监控等功能,而不改变真实对象的代码。

7. 代理模式的优缺点

优点:
  • 控制访问:代理模式可以用来控制对真实对象的访问,例如权限控制、延迟加载等。
  • 增强功能:可以在代理对象中增加额外的功能,例如缓存、日志记录、安全验证等,而无需修改真实对象的代码。
  • 降低耦合:客户端与真实对象的耦合度降低,客户端只与代理对象打交道,真实对象的变化不会直接影响到客户端。
缺点:
  • 增加复杂性:引入代理类可能增加系统的复杂度,尤其是如果代理对象的数量过多时,会使得系统变得更加难以维护。
  • 性能问题:代理模式引入了一个额外的对象,可能会导致一定的性能开销,尤其是在代理和真实对象交互频繁的情况下。

8. 总结

代理模式通过引入代理对象来控制对真实对象的访问,提供了更灵活的对象访问控制手段。它适用于延迟加载、权限控制、缓存等场景。通过代理,客户端可以与真实对象进行交互,而无需直接与真实对象打交道,从而降低了耦合度和系统的复杂性。在实际应用中,代理模式可以通过增强功能来提高系统的可扩展性和安全性。

版权声明
  1. 本文内容属于原创,欢迎转载,但请务必注明出处和作者,尊重原创版权。
  2. 转载时,请附带原文链接并注明"本文作者:扣丁梦想家
  3. 禁止未经授权的商业转载。

如果您有任何问题或建议,欢迎留言讨论。

相关推荐
ghost1439 小时前
C#学习第23天:面向对象设计模式
开发语言·学习·设计模式·c#
敲代码的 蜡笔小新13 小时前
【行为型之迭代器模式】游戏开发实战——Unity高效集合遍历与场景管理的架构精髓
unity·设计模式·c#·迭代器模式
敲代码的 蜡笔小新1 天前
【行为型之命令模式】游戏开发实战——Unity可撤销系统与高级输入管理的架构秘钥
unity·设计模式·架构·命令模式
m0_555762901 天前
D-Pointer(Pimpl)设计模式(指向实现的指针)
设计模式
小Mie不吃饭1 天前
【23种设计模式】分类结构有哪些?
java·设计模式·设计规范
君鼎2 天前
C++设计模式——单例模式
c++·单例模式·设计模式
敲代码的 蜡笔小新2 天前
【行为型之中介者模式】游戏开发实战——Unity复杂系统协调与通信架构的核心秘诀
unity·设计模式·c#·中介者模式
令狐前生2 天前
设计模式学习整理
学习·设计模式
敲代码的 蜡笔小新2 天前
【行为型之解释器模式】游戏开发实战——Unity动态公式解析与脚本系统的架构奥秘
unity·设计模式·游戏引擎·解释器模式
JANYI20182 天前
嵌入式设计模式基础--C语言的继承封装与多态
java·c语言·设计模式