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

代理设计模式

        代理设计模式是一种结构模式,它为 另一个对象提供占位符或代理,允许您控制对它的访问。

在实际应用程序中,您经常使用资源密集型、远程或敏感组件,例如数据库连接、第三方 API、文件系统或大型内存数据集。

有时您还想:
延迟或控制对实际实现的访问
添加额外的功能(例如日志记录、身份验证),而无需修改现有代码。
代理位于客户端和真实对象之间,拦截调用并可选择更改行为。

让我们通过一个真实世界的示例,看看如何应用代理模式来构建与昂贵或敏感资源的更安全、更智能、更可控的交互。

问题:急切加载
想象一下,您正在构建一个图片库应用程序。用户可以滚动浏览图像缩略图列表,当他们单击一个缩略图时, 会显示完整的高分辨率图像。

  1. 1. 图像界面
    我们定义了一个基本 接口来支持渲染行为:Image
public interface Image {void display();String getFileName();
}
  1. 2. 高分辨率图像实现
    此类表示加载和呈现的实际全尺寸图像。在构建它时,它会加载完整的图像数据——这故意缓慢且占用大量内存。
public class HighResolutionImage implements Image {private String fileName;private byte[] imageData; // Simulate large datapublic HighResolutionImage(String fileName) {this.fileName = fileName;loadImageFromDisk(); // Expensive operation!}private void loadImageFromDisk() {System.out.println("Loading image: " + fileName + " from disk (Expensive Operation)...");// Simulate disk read and memory allocationtry {Thread.sleep(2000); // Simulate delaythis.imageData = new byte[10 * 1024 * 1024]; // 10MB} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("Image " + fileName + " loaded successfully.");}@Overridepublic void display() {System.out.println("Displaying image: " + fileName);// Actual rendering logic would go here}@Overridepublic String getFileName() {return fileName;}
}
  1. 3. 天真的画廊应用程序
public class ImageGalleryAppV1 {public static void main(String[] args) {System.out.println("Application Started. Initializing images for gallery...");// Imagine we need to create image objects for a list of thumbnails// Even if the user never clicks them, they get loaded!Image image1 = new HighResolutionImage("photo1.jpg");Image image2 = new HighResolutionImage("photo2.png");Image image3 = new HighResolutionImage("photo3.gif");System.out.println("\nGallery initialized. User might view an image now.");// User clicks on image1System.out.println("User requests to display " + image1.getFileName());image1.display();// User clicks on image3System.out.println("\nUser requests to display " + image3.getFileName());image3.display();// image2 was loaded but never displayed by the user in this session. Waste of resources!System.out.println("\nApplication finished.");}    
}

这种方法有什么问题?

  1. 1. . 资源密集型初始化
    Every 在构建时加载其图像数据,即使用户从未查看过图像。这导致:HighResolutionImage
    应用程序启动缓慢
    不必要的内存消耗
    浪费的 I/O 带宽
    如果您的图库显示数十或数百个缩略图,这种方法很快就会成为瓶颈。
  2. 2. 无法控制访问
    如果您想:
    每次实际显示图像时都记录?
    在加载敏感图像之前添加权限检查?
    缓存以前加载的图像以供重用?

现在,您必须直接修改 类——混合职责、打破单一责任原则,或者更糟糕的是,跨客户端复制逻辑。HighResolutionImage

我们真正需要什么
我们需要一个解决方案,使我们能够:
将昂贵的图像数据加载推迟到实际需要时才进行。
添加额外的行为,如日志记录、访问控制或缓存,而无需更改现有 类。HighResolutionImage
维护相同的接口,以便不需要更改客户端代码。
这就是代理设计模式发挥作用的地方。

代理模式
代理设计模式为另一个对象 提供了一个替代对象或占位符来控制对它的访问。客户端不是直接与“真实”对象(例如,)交互,而是与实现相同接口的代理交互。HighResolutionImage

这允许代理执行额外的职责,例如延迟初始化、访问控制、日志记录或缓存,而无需更改原始类或客户端代码。

类图

主题(例如,Image)
定义 RealSubject 和 Proxy 共享的通用作的接口或抽象类。
这种抽象允许客户端可以互换地处理真实对象及其代理。

实主体(例如HighResolutionImage)
执行实际工作的 实际对象。
通常创建成本高昂,使用资源密集型,或者需要额外的控制层。
代理表示此对象并管理对它的访问。

代理(例如ImageProxy)
实现与 (即) 相同的接口,使其能够无缝地站进。RealSubjectImage
保存对真实对象的引用,并控制创建或访问它的时间和方式。
充当看门人,仅在适当的时候将调用委托给真实对象。

客户(例如ImageGalleryApp)
通过界面处理对象 。Subject
不需要知道它是与真实对象还是代理交互。
这种抽象使客户端代码保持干净、解耦和适应性强。
根据用例,代理可能采用不同的形式:

虚拟代理:推迟真实对象的创建,直到实际需要(延迟加载)。
保护代理:在允许访问某些作之前执行权限检查。
远程代理:处理网络上本地和远程对象之间的通信。
缓存代理: 高速缓存昂贵的结果,并避免重复调用实际主题。
智能代理:添加日志记录、引用计数或方法调用前后监控。

实现代理
现在让我们重构我们的图像库以使用代理设计模式。
我们不会急切地加载每个 ,而是使用一个代理来包装它并延迟加载,直到真正需要图像。HighResolutionImage

1:创建代理类
我们将实现 与 相同的接口,允许客户端互换使用它。在内部,它将保存对真实图像的引用,但仅在需要时初始化它。ImageProxyImageHighResolutionImage

public class ImageProxy implements Image {private String fileName;private HighResolutionImage realImage; // RealSubjectpublic ImageProxy(String fileName) {this.fileName = fileName;System.out.println("ImageProxy: Created for " + fileName + ". Real image not loaded yet.");}@Overridepublic String getFileName() {// Can safely return without loading the imagereturn fileName;}@Overridepublic void display() {// Lazy initialization: Load only when display() is calledif (realImage == null) {System.out.println("ImageProxy: display() requested for " + fileName + ". Loading high-resolution image...");realImage = new HighResolutionImage(fileName);} else {System.out.println("ImageProxy: Using cached high-resolution image for " + fileName);}// Delegate the display call to the real imagerealImage.display();}
}

2:更新客户端代码以使用代理
从客户端的角度来看,没有任何变化——它仍然与 .但现在,它不再预先处理重量级对象,而是获得一个轻量级代理,仅按需加载真实对象。Image

public class ImageGalleryAppV2 {public static void main(String[] args) {System.out.println("Application Started. Initializing image proxies for gallery...");// Create lightweight proxies instead of full image objectsImage image1 = new ImageProxy("photo1.jpg");Image image2 = new ImageProxy("photo2.png"); // Never displayedImage image3 = new ImageProxy("photo3.gif");System.out.println("\nGallery initialized. No images actually loaded yet.");System.out.println("Image 1 Filename: " + image1.getFileName()); // Does not trigger image load// User clicks on image1System.out.println("\nUser requests to display " + image1.getFileName());image1.display(); // Lazy loading happens here// User clicks on image1 againSystem.out.println("\nUser requests to display " + image1.getFileName() + " again.");image1.display(); // Already loaded; no loading delay// User clicks on image3System.out.println("\nUser requests to display " + image3.getFileName());image3.display(); // Triggers loading for image3System.out.println("\nApplication finished. Note: photo2.png was never loaded.");}
}

我们收获了什么?
让我们在这里回顾一下使用代理模式的优势:
延迟加载:仅在用户查看图像时才加载图像,从而缩短启动时间和内存使用。
干净的接口:客户端代码统一交互 ,不知道它是处理真实对象还是代理。Image
对真实对象没有代码更改:原始内容 保持不变。我们不必修改它来支持延迟加载。HighResolutionImage

可重用性: 可以重复用于其他优化,如日志记录、缓存或访问控制。ImageProxy
这是虚拟代理的完美用例 ——一种代理,它代表一个昂贵的对象,并将其创建推迟到绝对必要时。

通过仅引入一个小类 (),我们提高了性能、节省了内存,并保持了我们的设计干净、可扩展且易于维护——所有这些都无需触及原始图像类或更改客户端逻辑。ImageProxy

使用其他代理类型进行扩展
代理模式最强大的方面之一是 它可以很容易地扩展以支持不同的关注点(通常是同时的),而无需修改真实对象或显着更改客户端代码。

让我们探讨如何发展我们 不仅充当虚拟代理,而且充当:ImageProxy
保护代理 – 根据用户角色或权限限制访问。
日志记录代理 – 记录访问尝试和使用元数据。

  1. 1. 添加保护代理
    保护代理根据授权规则控制对敏感作的访问。例如,只有具有角色的用户才能 查看机密图像。ADMIN

我们可以将方法扩展 为 在加载或显示图像之前检查访问权限:display()ImageProxy

private boolean checkAccess(String userRole) {System.out.println("ProtectionProxy: Checking access for role: " + userRole + " on file: " + fileName);// Simulate a basic access control rulereturn "ADMIN".equals(userRole) || !fileName.contains("secret");}public void display(String userRole) {if (!checkAccess(userRole)) {System.out.println("ProtectionProxy: Access denied for " + fileName);return;}if (realImage == null) {System.out.println("ImageProxy: Loading image for authorized access....");realImage = new HighResolutionImage(fileName);}realImage.display();}

这种方法保持 了自由授权逻辑,同时在代理级别启用了细粒度的访问控制。HighResolutionImage

  1. 2. 添加日志记录代理
    日志记录代理拦截方法调用,并在将其转发到真实对象之前或之后记录它们。这对于审计、调试或使用情况分析特别有用。

以下是我们如何增强原始 方法:display()

@Override
public void display() {System.out.println("LoggingProxy: Attempting to display " + fileName + " at " + new java.util.Date());if (realImage == null) {System.out.println("ImageProxy: Lazy-loading image...");realImage = new HighResolutionImage(fileName);}realImage.display();System.out.println("LoggingProxy: Finished displaying " + fileName + " at " + new java.util.Date());
}

只需几行额外的代码, 现在就可以执行多个角色:ImageProxy
充当昂贵对象(虚拟代理)的替代品
延迟初始化直到需要(延迟加载)
限制对敏感内容的访问(保护代理)
记录映像访问和使用模式(日志记录代理)

所有这些都是透明地发生的,客户端或真实对象都不知道。

其他阅读材料:

https://pan.baidu.com/s/1c1oQItiA7nZxz8Rnl3STpw?pwd=yftc
https://pan.quark.cn/s/dec9e4868381

http://www.dtcms.com/a/349944.html

相关文章:

  • 俄罗斯情报机构推出新型安卓恶意软件,伪装成杀毒软件
  • SciPy科学计算与应用:SciPy入门与应用-科学计算与NumPy协同实践
  • 工业异常检测大模型(1)数据集、方法
  • 【git使用场景】本地仓库与远程仓库存在独立历史
  • Vulkan 学习路线图
  • Git 怎么仓库迁移?error: remote origin already exists.怎么解决
  • 定时器的原理
  • TensorFlow 深度学习 | Dataset API 数据读取详解
  • Open3D入门指南:3D数据处理与可视化利器
  • 初识神经网络——《深度学习入门:基于Python的理论与实现》
  • 昆仑万维开源 Matrix-3D大模型,正在开启“造物主”模式
  • 【智慧城市】2025年中国地质大学(武汉)暑期实训优秀作品(2):智慧城市西安与一带一路
  • pytest 并发执行用例(基于受限的测试资源)
  • imx6ull-驱动开发篇40——Linux RTC 驱动简介
  • 一道MySQL笔试题: 输出 100 以内质数
  • VIVO/OPPO手机,显示5G开关
  • 【SystemUI】锁屏来通知默认亮屏Wake模式
  • Mac 菜单栏多合一工具自荐:FancyTool
  • LeetCode算法日记 - Day 22: 提莫攻击、Z字形变换
  • 电影感人文街拍摆摊纪实摄影后期Lr调色教程,手机滤镜PS+Lightroom预设下载!
  • 从手术室到街头摄像头:多模态融合如何让AI“看得懂”万物?
  • 搭建ftp服务器(主动模式,被动模式)
  • Canvas 动态高度文本图片生成器
  • Linux 详谈Ext系列⽂件系统(一)
  • 嵌入式(ARM方向)面试常见问题及解答
  • 【ARM】MDK在debug模式下断点的类型
  • blazor 学习笔记--vscode debug
  • C++11(Linux/GCC)字节序工具
  • 2025年09月计算机二级Python选择题每日一练——第七期
  • 栈指针(Stack Pointer)是什么?