news 2026/4/16 18:59:48

设计模式:代理模式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
设计模式:代理模式

目录

一、核心角色

二、代理模式的分类

关键补充:动态代理(Spring AOP 的底层原理)

三、核心作用(解决的问题)

四、代理模式 vs 装饰者模式

五、在无人售货柜项目中的典型应用


代理模式是结构型设计模式的一种,核心思想是通过一个 “代理对象” 来控制对 “真实对象” 的访问,代理对象可以在真实对象的调用前后添加额外逻辑,同时对外隐藏真实对象的实现细节。

简单来说,代理模式就像生活中的中介:你租房不用直接找房东,而是通过中介(代理)完成看房、签约、缴费等流程,中介还会帮你筛选房源、处理售后问题。

一、核心角色

代理模式包含 4 个核心角色,以无人售货柜项目IoT设备通信场景为例:

  1. 抽象主题(Subject)定义真实对象和代理对象的共同接口,确保代理对象可以替代真实对象。

    java

    运行

    // 设备通信接口(抽象主题) public interface DeviceCommunicator { // 发送指令给售货柜硬件 void sendCommand(String deviceId, String command); // 接收设备上报数据 String receiveData(String deviceId); }
  2. 真实主题(Real Subject)实现抽象主题接口,是业务逻辑的实际执行者(真正和硬件交互的类)。

    java

    运行

    // 真实设备通信类(真实主题) public class RealDeviceCommunicator implements DeviceCommunicator { @Override public void sendCommand(String deviceId, String command) { // 实际的硬件通信逻辑:如通过MQTT/串口发送指令 System.out.println("向设备[" + deviceId + "]发送指令:" + command); } @Override public String receiveData(String deviceId) { // 模拟从硬件接收传感器数据(如库存、温度) return "设备[" + deviceId + "]上报数据:库存剩余50件,温度25℃"; } }
  3. 代理对象(Proxy)持有真实主题的引用,实现抽象主题接口,在调用真实对象方法时添加额外逻辑(如日志、权限校验、缓存)。

    java

    运行

    // 设备通信代理类(代理对象) public class DeviceCommunicatorProxy implements DeviceCommunicator { // 持有真实对象的引用 private final DeviceCommunicator realCommunicator; public DeviceCommunicatorProxy() { this.realCommunicator = new RealDeviceCommunicator(); } @Override public void sendCommand(String deviceId, String command) { // 前置增强:权限校验 + 日志记录 if (!checkPermission(deviceId)) { throw new RuntimeException("无权限操作设备:" + deviceId); } System.out.println("【代理】发送指令前日志:设备ID=" + deviceId + ",指令=" + command); // 调用真实对象的方法 realCommunicator.sendCommand(deviceId, command); // 后置增强:记录指令发送结果 System.out.println("【代理】发送指令成功"); } @Override public String receiveData(String deviceId) { // 前置增强:缓存校验(避免重复请求硬件) String cacheData = getCacheData(deviceId); if (cacheData != null) { return "【缓存数据】" + cacheData; } // 调用真实对象获取数据 String realData = realCommunicator.receiveData(deviceId); // 后置增强:缓存数据 setCacheData(deviceId, realData); return "【实时数据】" + realData; } // 模拟权限校验 private boolean checkPermission(String deviceId) { return deviceId.startsWith("CABINET_"); // 仅允许操作售货柜设备 } // 模拟本地缓存 private final Map<String, String> dataCache = new HashMap<>(); private String getCacheData(String deviceId) { return dataCache.get(deviceId); } private void setCacheData(String deviceId, String data) { dataCache.put(deviceId, data); } }
  4. 客户端(Client)只和代理对象交互,无需知道真实对象的存在。

    java

    运行

    public class Client { public static void main(String[] args) { // 使用代理对象,而非直接使用RealDeviceCommunicator DeviceCommunicator proxy = new DeviceCommunicatorProxy(); // 发送指令(自动触发权限校验和日志) proxy.sendCommand("CABINET_001", "OPEN_DOOR"); // 接收数据(首次获取实时数据,后续获取缓存数据) System.out.println(proxy.receiveData("CABINET_001")); System.out.println(proxy.receiveData("CABINET_001")); } }

二、代理模式的分类

根据代理对象的创建时机和方式,可以分为 3 种常见类型,对应不同的业务场景:

类型核心特点适用场景无人售货柜项目案例
静态代理代理类在编译期就已确定,和真实类一一对应业务逻辑固定、简单的场景上述的DeviceCommunicatorProxy,为设备通信添加固定的权限和缓存逻辑
动态代理代理类在运行期动态生成,无需手动编写代理类多个类需要相同的代理逻辑(如统一日志、事务)为所有微服务接口添加统一的多租户数据隔离拦截:通过 JDK 动态代理,在接口调用前自动拼接租户 ID 作为查询条件
远程代理代理对象和真实对象不在同一进程,通过网络通信分布式系统、跨服务调用售货柜云平台通过代理调用远程的支付结算服务:代理对象负责封装 HTTP 请求、处理网络异常、重试机制

关键补充:动态代理(Spring AOP 的底层原理)

在无人售货柜的微服务架构中,动态代理的应用远比静态代理广泛。例如,通过 Spring AOP 实现全局的接口日志、事务管理、多租户拦截,其底层就是动态代理。

多租户数据隔离为例,通过 JDK 动态代理实现统一拦截:

java

运行

// 租户上下文(存储当前请求的租户ID) public class TenantContext { private static final ThreadLocal<String> TENANT_ID = new ThreadLocal<>(); public static void setTenantId(String tenantId) { TENANT_ID.set(tenantId); } public static String getTenantId() { return TENANT_ID.get(); } } // 动态代理处理器 public class TenantProxyHandler implements InvocationHandler { private final Object target; // 真实对象(如Service层Bean) public TenantProxyHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前置增强:获取租户ID,修改查询参数(如给Mapper的参数添加tenantId) String tenantId = TenantContext.getTenantId(); if (tenantId != null && args != null) { for (int i = 0; i < args.length; i++) { if (args[i] instanceof BaseQuery) { ((BaseQuery) args[i]).setTenantId(tenantId); } } } // 执行真实方法 return method.invoke(target, args); } } // 客户端使用动态代理 public class DynamicProxyClient { public static void main(String[] args) { // 真实对象:如商品服务的Service GoodsService realService = new GoodsServiceImpl(); // 生成动态代理对象 GoodsService proxyService = (GoodsService) Proxy.newProxyInstance( realService.getClass().getClassLoader(), realService.getClass().getInterfaces(), new TenantProxyHandler(realService) ); // 设置当前租户ID TenantContext.setTenantId("TENANT_001"); // 调用代理方法,自动添加租户ID条件 proxyService.queryGoods(new GoodsQuery()); } }

三、核心作用(解决的问题)

  1. 功能增强在不修改真实对象代码的前提下,添加额外逻辑(如日志、缓存、权限、事务),符合开闭原则
  2. 隐藏细节对客户端隐藏真实对象的实现细节(如硬件通信的协议、远程服务的地址),降低客户端的使用成本。
  3. 控制访问限制对真实对象的直接访问(如权限校验、限流、熔断),保护核心业务逻辑。

四、代理模式 vs 装饰者模式

很多开发者会混淆这两种模式,核心区别如下:

维度代理模式装饰者模式
核心目的控制对真实对象的访问给真实对象添加功能
关系代理对象持有真实对象的引用,是 “控制者”装饰者和真实对象实现同一接口,是 “增强者”
场景权限校验、远程调用、缓存功能扩展(如给 IO 流添加缓冲、加密功能)

五、在无人售货柜项目中的典型应用

  1. IoT 设备通信层:用静态代理添加指令日志、设备权限校验、数据缓存
  2. 微服务接口层:用动态代理(Spring AOP)实现多租户数据隔离、接口限流、全局异常处理
  3. 远程服务调用:用远程代理(如 Feign 客户端)封装跨服务调用的网络请求、重试、降级逻辑
  4. 支付结算模块:用代理模式封装不同支付渠道(微信、支付宝)的调用细节,对上层提供统一接口。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 23:26:47

如何快速部署摄像头监控系统:5分钟完成camera.ui完整配置指南

如何快速部署摄像头监控系统&#xff1a;5分钟完成camera.ui完整配置指南 【免费下载链接】camera.ui NVR like user Interface for RTSP capable cameras 项目地址: https://gitcode.com/gh_mirrors/ca/camera.ui camera.ui是一款功能强大的开源摄像头管理平台&#xf…

作者头像 李华
网站建设 2026/4/16 18:26:55

HarmonyOS 应用草稿箱功能设计方案(安全可靠+轻量化存储)

大家好&#xff0c;今天给大家带来的是如何在在HarmonyOS上实现草稿箱功能&#xff0c;&#xff0c;在保障草稿不丢失的同时&#xff0c;避免冗余数据占用过多设备存储空间&#xff0c;在面正文开始。 文章目录一、 本地草稿数据结构设计&#xff08;规范有序&#xff0c;易存易…

作者头像 李华
网站建设 2026/4/16 18:58:38

边缘AI设备锂电池保护电路的终极设计指南

边缘AI设备锂电池保护电路的终极设计指南 【免费下载链接】AI-on-the-edge-device Easy to use device for connecting "old" measuring units (water, power, gas, ...) to the digital world 项目地址: https://gitcode.com/GitHub_Trending/ai/AI-on-the-edge-d…

作者头像 李华
网站建设 2026/4/6 6:17:07

使用PyTorch-CUDA镜像轻松运行Transformer和CNN模型

使用PyTorch-CUDA镜像轻松运行Transformer和CNN模型 在深度学习项目中&#xff0c;最让人头疼的往往不是模型设计本身&#xff0c;而是环境配置——“为什么我的代码在别人机器上跑不通&#xff1f;”、“CUDA版本不匹配怎么办&#xff1f;”、“装个PyTorch怎么还要折腾驱动&a…

作者头像 李华
网站建设 2026/4/17 5:25:26

PyTorch-CUDA镜像适合做自然语言处理吗?答案是肯定的

PyTorch-CUDA镜像适合做自然语言处理吗&#xff1f;答案是肯定的 在如今这个大模型遍地开花的时代&#xff0c;谁还没跑过几个BERT、微调过一次GPT&#xff1f;但每次换机器、上服务器&#xff0c;是不是总要花半天时间折腾环境&#xff1a;CUDA版本对不对、cuDNN装没装、PyTor…

作者头像 李华