首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >23种设计模式之代理模式

23种设计模式之代理模式

作者头像
紫风
发布2025-10-14 18:36:40
发布2025-10-14 18:36:40
9500
代码可运行
举报
运行总次数:0
代码可运行

以下是 代理模式 (Proxy Pattern) 的详细介绍,包含定义、优缺点、应用场景及代码实现:

一、代理模式概述
  • 英文名称:Proxy
  • 核心目标为其他对象提供一种代理以控制对该对象的访问,增强对目标对象的访问控制或功能扩展。
  • 设计思想:通过代理对象作为中间层,实现访问控制、延迟加载、日志记录、缓存等附加功能,客户端通过代理间接操作目标对象。

二、优缺点
优点
  1. 职责清晰:目标对象专注于核心逻辑,代理处理附加功能(如权限校验)。
  2. 高扩展性:通过代理扩展功能,无需修改目标对象(符合开闭原则)。
  3. 保护目标对象:代理可控制客户端对真实对象的访问权限。
缺点
  1. 复杂度增加:引入代理层会增加系统结构和调用链路。
  2. 性能损耗:动态代理基于反射,可能略微降低执行效率。

三、应用场景
  1. 远程代理:访问远程对象(如 RPC 调用)。
  2. 虚拟代理:延迟加载大资源对象(如图片加载)。
  3. 安全代理:控制敏感对象的访问权限。
  4. 日志/监控代理:记录方法调用日志或性能指标。
  5. 缓存代理:缓存计算结果,避免重复处理。

四、代码实现与注释

以下通过 图片加载系统 的案例演示代理模式,包含静态代理和动态代理两种实现:


1. 静态代理实现
(1) 抽象主题接口(图片加载)
代码语言:javascript
代码运行次数:0
运行
复制
/**
 * 抽象主题接口:定义图片加载行为
 */
public interface Image {
    void display();
}
(2) 真实主题类(实际图片加载)
代码语言:javascript
代码运行次数:0
运行
复制
/**
 * 真实主题类:实现图片加载逻辑
 */
public class RealImage implements Image {
    private final String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();  // 初始化时直接加载图片
    }

    private void loadFromDisk() {
        System.out.println("从磁盘加载图片: " + filename);
    }

    @Override
    public void display() {
        System.out.println("显示图片: " + filename);
    }
}
(3) 代理类(延迟加载图片)
代码语言:javascript
代码运行次数:0
运行
复制
/**
 * 静态代理类:延迟加载图片(仅在 display() 时加载)
 */
public class ProxyImage implements Image {
    private RealImage realImage;  // 持有真实对象的引用
    private final String filename;

    public ProxyImage(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);  // 延迟初始化
        }
        realImage.display();
    }
}
(4) 客户端调用
代码语言:javascript
代码运行次数:0
运行
复制
public class Client {
    public static void main(String[] args) {
        // 使用代理对象(此时未加载图片)
        Image image = new ProxyImage("test.jpg");
        
        // 调用 display() 时才真正加载图片
        image.display();
    }
}
(5) 输出结果
代码语言:javascript
代码运行次数:0
运行
复制
从磁盘加载图片: test.jpg
显示图片: test.jpg

2. 动态代理实现(基于 JDK)
(1) 抽象主题接口(用户服务)
代码语言:javascript
代码运行次数:0
运行
复制
/**
 * 抽象主题接口:用户服务
 */
public interface UserService {
    void addUser(String name);
    void deleteUser(String name);
}
(2) 真实主题类(用户服务实现)
代码语言:javascript
代码运行次数:0
运行
复制
/**
 * 真实主题类:用户服务实现
 */
public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String name) {
        System.out.println("添加用户: " + name);
    }

    @Override
    public void deleteUser(String name) {
        System.out.println("删除用户: " + name);
    }
}
(3) 动态代理处理器(日志记录)
代码语言:javascript
代码运行次数:0
运行
复制
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 动态代理处理器:为所有方法添加日志
 */
public class LogInvocationHandler implements InvocationHandler {
    private final Object target;  // 被代理的真实对象

    public LogInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置增强:记录方法名和参数
        System.out.println("[日志] 调用方法: " + method.getName() + ", 参数: " + args[0]);

        // 调用真实对象的方法
        Object result = method.invoke(target, args);

        // 后置增强(此处省略)
        return result;
    }
}
(4) 客户端调用(动态生成代理对象)
代码语言:javascript
代码运行次数:0
运行
复制
import java.lang.reflect.Proxy;

public class Client {
    public static void main(String[] args) {
        // 创建真实对象
        UserService realService = new UserServiceImpl();

        // 创建动态代理对象
        UserService proxyService = (UserService) Proxy.newProxyInstance(
            realService.getClass().getClassLoader(),
            realService.getClass().getInterfaces(),
            new LogInvocationHandler(realService)
        );

        // 通过代理对象调用方法
        proxyService.addUser("Alice");
        proxyService.deleteUser("Bob");
    }
}
(5) 输出结果
代码语言:javascript
代码运行次数:0
运行
复制
[日志] 调用方法: addUser, 参数: Alice
添加用户: Alice
[日志] 调用方法: deleteUser, 参数: Bob
删除用户: Bob

五、模式结构图
代码语言:javascript
代码运行次数:0
运行
复制
+----------------+          +----------------+
|   Subject      | <------+ |   Proxy        |
+----------------+          +----------------+
| +request()     |          | -realSubject:Subject|
+----------------+          | +request()     |
         ^                  +----------------+
         |                         ^
         |                         |
+----------------+          +----------------+
| RealSubject    |          |                |
+----------------+          +----------------+
| +request()     |          |                |
+----------------+          +----------------+

六、与其他模式的关系
  1. 装饰器模式:代理模式控制访问,装饰器模式增强功能。
  2. 适配器模式:代理模式接口不变,适配器模式转换接口。
  3. 外观模式:代理模式代理单个对象,外观模式封装子系统接口。

七、最佳实践
  1. 优先动态代理:减少重复代码,增强灵活性(如 Spring AOP)。
  2. CGLIB 代理:针对无接口的类,使用字节码增强库(如 Enhancer)。
  3. 代理池管理:对远程代理或高开销代理对象使用池化技术优化性能。

八、总结
  • 核心价值:通过代理层实现访问控制和功能扩展,解耦核心逻辑与附加操作。
  • 适用场景:需要增强对象访问控制、延迟加载、日志监控等非功能性需求的系统。
  • 关键实现:抽象主题接口 + 真实主题类 + 代理类(静态/动态)。

代理模式在 Java 生态中广泛应用,例如:

  • Spring Framework:AOP 基于动态代理实现日志、事务管理。
  • MyBatis:Mapper 接口通过代理绑定 SQL 映射。
  • RMI:远程方法调用通过代理屏蔽网络通信细节。

掌握代理模式能显著提升系统架构的灵活性和可维护性。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、代理模式概述
  • 二、优缺点
    • 优点:
    • 缺点:
  • 三、应用场景
  • 四、代码实现与注释
    • 1. 静态代理实现
      • (1) 抽象主题接口(图片加载)
      • (2) 真实主题类(实际图片加载)
      • (3) 代理类(延迟加载图片)
      • (4) 客户端调用
      • (5) 输出结果
    • 2. 动态代理实现(基于 JDK)
      • (1) 抽象主题接口(用户服务)
      • (2) 真实主题类(用户服务实现)
      • (3) 动态代理处理器(日志记录)
      • (4) 客户端调用(动态生成代理对象)
      • (5) 输出结果
  • 五、模式结构图
  • 六、与其他模式的关系
  • 七、最佳实践
  • 八、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档