当前位置: 首页 > news >正文

结构型模式:代理模式

什么是代理模式?

代理模式很像我们生活中的"中间人"。想象一下,当你请明星参加活动时,你通常不会直接联系明星本人,而是联系他的经纪人。这个经纪人就是一个"代理",他代表明星处理各种事务,筛选请求,安排日程等。

在编程中,代理模式也是这样工作的:我们创建一个"代理对象",它控制着对另一个"真实对象"的访问。当你想使用真实对象时,你实际上是在和代理对象打交道。

为什么要用代理模式?

思考场景:

  • 你想在访问某个重要文件前检查使用者的权限
  • 你需要延迟加载一个很大的图片,直到真正需要显示它时
  • 你希望记录每次对数据库的访问操作
  • 你要在网络上远程调用另一台计算机上的程序

这些场景都很适合使用代理模式,它可以帮我们:

  1. 控制访问:像保安一样,检查谁能访问对象
  2. 延迟加载:懒惰一点,等真正需要时才创建开销大的对象
  3. 增加功能:在不改变原对象的情况下,添加新功能
  4. 远程访问:让远程对象看起来就像本地对象一样易用

代理模式长什么样?

用一个餐厅点餐的例子来说明。顾客(客户端)不直接告诉厨师(真实对象)做什么菜,而是告诉服务员(代理),服务员再把请求传给厨师。

// 菜单接口
interface FoodService {void orderFood(String food);
}// 厨师(真实对象)
class Chef implements FoodService {@Overridepublic void orderFood(String food) {System.out.println("厨师正在烹饪: " + food);}
}// 服务员(代理对象)
class Waiter implements FoodService {private Chef chef = new Chef();@Overridepublic void orderFood(String food) {System.out.println("服务员记录订单: " + food);// 检查库存if ("鱼翅".equals(food)) {System.out.println("抱歉,鱼翅已售罄");return;}// 转发给厨师chef.orderFood(food);System.out.println("服务员准备上菜: " + food);}
}// 顾客使用
class Customer {public static void main(String[] args) {FoodService waiter = new Waiter();waiter.orderFood("宫保鸡丁");waiter.orderFood("鱼翅");}
}

在这个例子中,Waiter(服务员)就是一个代理,它实现了和Chef(厨师)相同的接口,但在转发请求前后添加了额外的处理。

代理模式有哪些种类?

1. 静态代理:写死在代码里的代理

上面餐厅的例子就是静态代理。代理关系在写代码时就确定了,服务员只能代理厨师。

生活例子:固定的售票窗口只能卖特定线路的车票。

2. 动态代理:灵活多变的代理

不用事先为每个对象写好代理类,而是在程序运行时动态创建代理。

生活例子:万能中介,今天代理房屋出租,明天代理二手车买卖。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 动态代理处理器
class DynamicProxyHandler implements InvocationHandler {private Object target; // 可以是任何对象public DynamicProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("开始处理: " + method.getName());// 调用目标对象的方法Object result = method.invoke(target, args);System.out.println("处理完成: " + method.getName());return result;}
}// 动态代理示例
public class DynamicProxyDemo {public static void main(String[] args) {// 创建真实对象Chef chef = new Chef();// 创建动态代理FoodService proxy = (FoodService) Proxy.newProxyInstance(FoodService.class.getClassLoader(),new Class<?>[] { FoodService.class },new DynamicProxyHandler(chef));// 使用代理proxy.orderFood("糖醋排骨");}
}

3. 远程代理:远在天边,近在眼前

让远程对象看起来像本地对象一样。

生活例子:你在国内用支付宝付款,但实际上商品在美国,支付宝作为代理处理了跨国支付细节。

4. 保护代理:守门员

控制对敏感对象的访问。

生活例子:保安检查你的门禁卡,确认你有权限才让你进入大楼。

5. 虚拟代理:按需加载

延迟创建开销大的对象,直到真正需要。

生活例子:你打开网页时,图片可能显示一个占位符,然后慢慢加载出来。

class HeavyImage implements Image {private String filename;public HeavyImage(String filename) {this.filename = filename;loadFromDisk();}private void loadFromDisk() {System.out.println("加载大图片: " + filename + "(这很慢)");// 模拟耗时操作try { Thread.sleep(1000); } catch (InterruptedException e) { }}public void display() {System.out.println("显示: " + filename);}
}class ImageProxy implements Image {private String filename;private HeavyImage realImage;public ImageProxy(String filename) {this.filename = filename;}public void display() {// 延迟加载,直到真正需要显示时if (realImage == null) {realImage = new HeavyImage(filename);}realImage.display();}
}

实际生活中的代理模式

明星和经纪人

  • 明星:真实对象
  • 经纪人:代理
  • 粉丝/商家:客户端

经纪人负责筛选邀约、谈判报酬、安排日程,保护明星不被骚扰。

网购和电商平台

  • 生产厂家:真实对象
  • 电商平台:代理
  • 消费者:客户端

淘宝、京东等平台作为代理,负责展示商品、处理支付、物流等。

法律代理

  • 法律:真实对象
  • 律师:代理
  • 当事人:客户端

律师代表当事人处理法律事务,提供专业建议和服务。

实用场景示例:图片加载器

假设我们在开发一个相册应用,需要显示大量高清图片。如果一次性加载所有图片,会很慢且浪费内存。我们可以使用代理模式来延迟加载图片:

interface Image {void display();
}// 真实图片(重量级对象)
class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadFromDisk();}private void loadFromDisk() {System.out.println("加载图片:" + filename);// 模拟耗时的加载过程try { Thread.sleep(1000); } catch (InterruptedException e) { }}@Overridepublic void display() {System.out.println("显示图片:" + filename);}
}// 图片代理
class ProxyImage implements Image {private String filename;private RealImage realImage;public ProxyImage(String filename) {this.filename = filename;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(filename);}realImage.display();}
}// 相册应用
public class PhotoAlbum {public static void main(String[] args) {// 创建相册(使用代理)Image[] album = new Image[5];album[0] = new ProxyImage("高清风景1.jpg");album[1] = new ProxyImage("高清风景2.jpg");album[2] = new ProxyImage("高清风景3.jpg");album[3] = new ProxyImage("高清风景4.jpg");album[4] = new ProxyImage("高清风景5.jpg");// 浏览相册(只有查看的图片才会被加载)System.out.println("打开相册...");// 用户只查看了第3张图片album[2].display();}
}

实用场景示例:权限控制

假设我们有一个文件系统,不同用户有不同的访问权限:

// 文件接口
interface File {String read();void write(String content);
}// 真实文件
class RealFile implements File {private String name;private String content;public RealFile(String name) {this.name = name;this.content = "这是" + name + "的内容";}@Overridepublic String read() {System.out.println("读取文件: " + name);return content;}@Overridepublic void write(String content) {System.out.println("写入文件: " + name);this.content = content;}
}// 文件访问代理
class FileAccessProxy implements File {private RealFile realFile;private String user;public FileAccessProxy(String filename, String user) {this.realFile = new RealFile(filename);this.user = user;}@Overridepublic String read() {// 所有用户都可以读取return realFile.read();}@Overridepublic void write(String content) {// 检查写入权限if ("admin".equals(user)) {realFile.write(content);} else {System.out.println("权限不足:用户 " + user + " 没有写入权限");}}
}// 文件系统
public class FileSystem {public static void main(String[] args) {// 普通用户访问File userFile = new FileAccessProxy("用户数据.txt", "张三");System.out.println(userFile.read());  // 允许读取userFile.write("尝试修改内容");  // 拒绝写入System.out.println();// 管理员访问File adminFile = new FileAccessProxy("用户数据.txt", "admin");System.out.println(adminFile.read());  // 允许读取adminFile.write("管理员修改的内容");  // 允许写入}
}

代理模式的优点

  1. 单一职责:真实对象专注核心功能,代理对象负责控制逻辑
  2. 扩展性好:不改变原对象,就能在外部添加功能
  3. 保护真实对象:限制对真实对象的直接访问
  4. 降低系统耦合度:客户端和真实对象不直接交互

代理模式的缺点

  1. 增加复杂度:新增了代理类,系统更复杂
  2. 可能降低性能:因为多了一层调用,特别是动态代理
  3. 可能引入不透明性:客户端不知道是在和代理打交道还是真实对象

代理模式和其他模式的区别

代理模式 vs 装饰器模式

  • 代理模式:控制对象访问
  • 装饰器模式:扩展对象功能

区别在于意图:门卫(代理)决定是否让你进入,而化妆师(装饰器)则是让你看起来更漂亮。

代理模式 vs 适配器模式

  • 代理模式:接口相同,加入控制
  • 适配器模式:转换不兼容的接口

区别在于:翻译(适配器)帮你和说不同语言的人交流,而律师(代理)则是以你的名义和法官交流。

什么时候用代理模式?

当你遇到这些情况时,考虑使用代理模式:

  1. 需要控制对某个对象的访问
  2. 需要在不修改已有代码的情况下添加功能
  3. 对象创建成本高,需要延迟初始化
  4. 需要在远程操作中隐藏复杂性
  5. 需要统一处理对多个对象的访问(如缓存、日志)

如何在实际项目中应用代理模式?

  1. 确定真实对象:明确需要被代理的对象
  2. 设计公共接口:代理和真实对象需要实现相同的接口
  3. 实现代理类:基于需求添加额外功能
  4. 选择代理类型:静态代理简单直接,动态代理更灵活
  5. 考虑性能影响:避免在性能关键路径上使用过于复杂的代理

总结

代理模式就像生活中的"中间人",它站在客户和真实对象之间,控制和扩展对真实对象的访问。无论是权限控制、延迟加载,还是增加额外功能,代理模式都能优雅地解决这些问题。

关键是理解代理模式的核心思想:通过引入一个新的对象来控制对原对象的访问。一旦掌握了这个思想,你就能在各种情景中灵活运用代理模式,让你的代码更加健壮和易于扩展。

http://www.xdnf.cn/news/513127.html

相关文章:

  • 改进模糊C均值时序聚类+编码器状态识别!IPOA-FCM-Transformer组合模型
  • 牛客网NC276055:三根木棒能否组成三角形问题详解(ACM中的A题)
  • 【C++】尾置返回类型(Trailing Return Type)总结
  • 多模态大语言模型arxiv论文略读(八十)
  • vscode优化使用体验篇(快捷键)
  • React 19版本refs也支持清理函数了。
  • 【C++】set、map 容器的使用
  • Java 中 == 与 equals() 详解
  • 索引与数据结构、并行算法
  • LlamaIndex中应用自定义提示词提升回答质量
  • go语言协程调度器 GPM 模型
  • 华为云Flexus+DeepSeek征文|基于华为云Flexus云服务的Dify 快速构建聊天助手
  • 目标检测新突破:用MSBlock打造更强YOLOv8
  • 如何使用WordPress创建美食博客
  • 跨平台多用户环境下PDF表单“序列号生成的服务器端方案“
  • 如何实现RTSP和RTMP低至100-200ms的延迟:直播SDK的技术突破
  • Metasploit框架与网络安全攻防技术解析
  • 标准库、HAl库和LL库(PC13初始化)
  • 【甲方安全建设】Python 项目静态扫描工具 Bandit 安装使用详细教程
  • 视差场(disparity field)
  • Linux之基础IO
  • MySQL 数据库备份与还原
  • iOS APP启动页及广告页的实现
  • 赋予AI更强的“思考”能力
  • 动态规划(4)可视化理解:图形化思考
  • Tomcat简述介绍
  • 10.8 LangChain三大模块深度实战:从模型交互到企业级Agent工具链全解析
  • 企业级小程序APP用户数据查询系统安全脆弱性分析及纵深防御体系构建
  • JUC入门(二)
  • [创业之路-362]:企业战略管理案例分析-3-战略制定-华为使命、愿景、价值观的演变过程