常用设计模式:代理模式

news/2025/11/12 10:40:40/文章来源:https://www.cnblogs.com/guangzan/p/19212489

什么是代理模式?

代理模式是一种结构型设计模式,它允许你提供一个替代物或占位符来控制对另一个对象的访问。代理对象充当原始对象的接口,客户端通过代理来间接访问原始对象,从而可以在不改变原始对象代码的情况下添加额外的功能。

代理模式特别有用,因为我们可以利用接口和类型系统来确保代理和真实对象具有相同的接口。

代理模式(Proxy Pattern) 的核心思想是:不直接访问目标对象,而是通过一个“代理对象(Proxy)”来间接访问。代理对象可以在调用目标对象的前后,执行额外的逻辑。

image

  1. 服务接口 (Service Interface) 声明了服务接口。 代理必须遵循该接口才能伪装成服务对象。
  2. 服务 (Service) 类提供了一些实用的业务逻辑。
  3. 代理 (Proxy) 类包含一个指向服务对象的引用成员变量。 代理完成其任务 (例如延迟初始化、 记录日志、 访问控制和缓存等) 后会将请求传递给服务对象。
  4. 客户端 (Client) 能通过同一接口与服务或代理进行交互, 所以你可在一切需要服务对象的代码中使用代理。

为什么需要代理模式?

在实际项目开发中,我们经常会遇到这样的需求:

  • 你需要在图片加载时显示一个加载动画
  • 你想要延迟创建开销很大的对象
  • 你需要控制对敏感对象的访问权限
  • 你想在某个对象被访问、调用之前或之后,增加一层控制逻辑(比如日志记录、权限验证、缓存、懒加载、远程调用等)

这类场景的典型解决方案,就是代理模式(Proxy Pattern)

代理模式的类型

1. 虚拟代理(延迟加载)

interface Image {display(): void;
}class RealImage implements Image {private filename: string;constructor(filename: string) {this.filename = filename;this.loadFromDisk();}private loadFromDisk(): void {console.log(`Loading ${this.filename} from disk...`);}display(): void {console.log(`Displaying ${this.filename}`);}
}class ImageProxy implements Image {private realImage: RealImage | null = null;private filename: string;constructor(filename: string) {this.filename = filename;}display(): void {if (this.realImage === null) {this.realImage = new RealImage(this.filename);}this.realImage.display();}
}

2. 保护代理(访问控制)

interface Database {query(sql: string): any[];
}class RealDatabase implements Database {query(sql: string): any[] {console.log(`Executing: ${sql}`);return [{ result: 'data' }];}
}class ProtectedDatabaseProxy implements Database {private realDatabase: RealDatabase;private userRole: string;constructor(userRole: string) {this.realDatabase = new RealDatabase();this.userRole = userRole;}query(sql: string): any[] {if (this.userRole !== 'admin' && sql.toLowerCase().includes('delete')) {throw new Error('Permission denied: Only admins can execute DELETE queries');}return this.realDatabase.query(sql);}
}

3. 日志代理

interface Calculator {add(a: number, b: number): number;multiply(a: number, b: number): number;
}class SimpleCalculator implements Calculator {add(a: number, b: number): number {return a + b;}multiply(a: number, b: number): number {return a * b;}
}class LoggingCalculatorProxy implements Calculator {private calculator: Calculator;constructor(calculator: Calculator) {this.calculator = calculator;}add(a: number, b: number): number {console.log(`Calling add with ${a} and ${b}`);const result = this.calculator.add(a, b);console.log(`Result: ${result}`);return result;}multiply(a: number, b: number): number {console.log(`Calling multiply with ${a} and ${b}`);const result = this.calculator.multiply(a, b);console.log(`Result: ${result}`);return result;}
}

实际应用示例:API 请求代理

让我们看一个更实际的例子——创建一个 API 请求代理,包含缓存和重试机制:

interface ApiClient {get(url: string): Promise<any>;post(url: string, data: any): Promise<any>;
}class RealApiClient implements ApiClient {async get(url: string): Promise<any> {const response = await fetch(url);return response.json();}async post(url: string, data: any): Promise<any> {const response = await fetch(url, {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify(data)});return response.json();}
}class SmartApiProxy implements ApiClient {private realClient: ApiClient;private cache: Map<string, { data: any; timestamp: number }> = new Map();private readonly CACHE_DURATION = 5 * 60 * 1000; // 5分钟constructor(realClient: ApiClient) {this.realClient = realClient;}async get(url: string): Promise<any> {const cached = this.cache.get(url);// 检查缓存是否有效if (cached && Date.now() - cached.timestamp < this.CACHE_DURATION) {console.log(`Returning cached data for ${url}`);return cached.data;}// 实现重试机制let lastError: Error;for (let attempt = 1; attempt <= 3; attempt++) {try {console.log(`Attempt ${attempt} for ${url}`);const data = await this.realClient.get(url);// 更新缓存this.cache.set(url, { data, timestamp: Date.now() });return data;} catch (error) {lastError = error as Error;if (attempt < 3) {await this.delay(1000 * attempt); // 指数退避}}}throw lastError!;}async post(url: string, data: any): Promise<any> {// POST 请求不缓存,但实现重试let lastError: Error;for (let attempt = 1; attempt <= 3; attempt++) {try {const result = await this.realClient.post(url, data);return result;} catch (error) {lastError = error as Error;if (attempt < 3) {await this.delay(1000 * attempt);}}}throw lastError!;}private delay(ms: number): Promise<void> {return new Promise(resolve => setTimeout(resolve, ms));}
}

使用示例

// 虚拟代理使用
const imageProxy = new ImageProxy('photo.jpg');
// 此时图片尚未加载
imageProxy.display(); // 第一次调用时加载并显示// 保护代理使用
const userDatabase = new ProtectedDatabaseProxy('user');
const adminDatabase = new ProtectedDatabaseProxy('admin');userDatabase.query('SELECT * FROM users'); // 正常执行
// userDatabase.query('DELETE FROM users'); // 抛出错误// 智能API代理使用
const apiClient = new SmartApiProxy(new RealApiClient());async function example() {// 第一次请求,从网络获取并缓存const data1 = await apiClient.get('https://api.example.com/data');// 第二次请求,返回缓存数据const data2 = await apiClient.get('https://api.example.com/data');
}

真实案例

Spring AOP

Spring AOP 使用代理模式来实现对目标对象的增强(如日志、事务、权限控制等)。

@Service
public class UserService {@Transactionalpublic void createUser(String name) {// 数据库操作}
}
  • Spring 会为 UserService 创建一个代理对象(JDK 动态代理或 CGLIB 代理)。
  • 当你调用 userService.createUser(...) 时,实际调用的是代理对象的方法。
  • 代理对象在方法执行前后插入事务管理逻辑(如开启事务、提交、回滚等)。

代理模式的优缺点

优点:

  • 开闭原则:可以在不修改真实对象的情况下扩展功能
  • 职责清晰:代理对象专注于控制访问,真实对象专注于业务逻辑
  • 延迟加载:可以优化性能,只在需要时创建昂贵对象
  • 访问控制:可以轻松添加权限检查

缺点:

  • 复杂度增加:引入了额外的抽象层
  • 响应延迟:代理调用可能比直接调用稍慢
  • 可能过度设计:简单场景下可能不需要代理模式

何时使用代理模式?

  • 需要延迟创建开销很大的对象时
  • 需要控制对原始对象的访问权限时
  • 需要在对象访问前后添加额外逻辑时
  • 需要为远程对象提供本地代表时(远程代理)
  • 需要为消耗大量内存的对象提供轻量级代表时

总结

代理模式是一种在不修改原有对象的前提下,通过中间层实现访问控制与逻辑增强的模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/963125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年山东直流电机维修公司权威推荐榜单:主轴电机维修/永磁电机维修/大型电机维修服务商精选

在山东的工业体系中,直流电机作为许多关键设备的动力核心,其稳定运行直接关系到生产效率和经济效益。专业、及时的维修保养服务是保障电机长周期安全运行的关键。本文将基于技术实力、服务响应、行业口碑等多维度评估…

AI元人文:价值原语化——构建从个体到文明的协同元代码

AI元人文:价值原语化——构建从个体到文明的协同元代码 引言:元时代的协同困境与范式革命 全球化与人工智能的深度交织,将人类文明带入了一个被称为“元时代”的新纪元。在这个时代,技术能力呈指数级增长,但人类协…

神经元为什么要设置偏置bias

这个问题问到了神经网络的核心设计逻辑!神经元设置偏置(bias)的核心作用是调整模型的“激活门槛”,让模型能更灵活地拟合数据规律。 核心结论 偏置是神经元的“偏移量”,用于控制激活函数被触发的难易程度,本质是…

2025 年 11 月柏尔地板厂家推荐排行榜,定制地板,实木地板,高端定制,实木地热,实木双锁扣地板公司精选

2025年11月柏尔地板厂家推荐排行榜:定制地板、实木地板、高端定制、实木地热、实木双锁扣地板公司精选 随着家居消费升级和健康生活理念的普及,实木地板行业正迎来新一轮发展机遇。特别是在高端定制、实木地热、实木…

2025年11月离婚房产律师推荐榜:许阿赛马赛男领衔五强对比评测

离婚房产分割往往牵动情感与资产双重敏感神经:一方担心隐匿资产,一方焦虑居住权与贷款责任;父母出资、婚前首付、婚后增值、公司股权混同,每一环节都可能成为法庭争议焦点。2025年,一线城市房价高位横盘,法院对“…

2025年激光焊翅片管供应商权威推荐榜单:翅片管加热器/钢管轧铝翅片管/空气散热器供应商精选

在当今工业换热领域,激光焊翅片管作为一种高效传热元件,其市场需求持续增长。根据Grand View Research的最新研究报告,全球换热器市场规模预计到2030年将达到226.2亿美元,2023年至2030年的复合年增长率为4.8%。在这…

VonaJS: 直观好用的分布式锁

VonaJS 基于Redlock提供了直观、易用的分布式锁分布式锁 VonaJS 基于Redlock提供了直观、易用的分布式锁 创建分布式锁 比如,在模块 demo-student 中创建分布式锁 1. Cli命令 $ vona :create:bean meta redlock --mod…

实用指南:计算机视觉(opencv)——实时颜色检测

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025 年 11 月悬浮炉厂家推荐排行榜,真空悬浮炉,真空感应悬浮炉,50kg悬浮炉,30kg悬浮炉,15kg悬浮炉,5kg悬浮炉公司精选

2025年11月悬浮炉厂家推荐排行榜:真空悬浮炉、真空感应悬浮炉及多规格悬浮炉公司精选 一、行业技术背景与发展现状 悬浮熔炼技术作为特种冶金装备领域的重要分支,近年来在高端材料制备、航空航天、新能源等领域展现出…

2025 年 11 月凝壳炉厂家推荐排行榜,真空感应凝壳炉,真空自耗凝壳炉,150kg真空凝壳炉,160kg真空凝壳炉,250kg真空凝壳炉,1t真空凝壳炉公司推荐

2025年11月凝壳炉厂家推荐排行榜:真空感应与真空自耗凝壳炉专业指南 行业技术背景与发展现状 凝壳炉作为特种冶金装备的核心设备,在高端材料制备领域发挥着不可替代的作用。随着新材料产业的快速发展,真空感应凝壳炉…

企业安全-互联网暴露面风险收敛

企业安全-互联网暴露面风险收敛企业容易遭受网络攻击的地方有两大块:员工使用的互联网终端(本章不讨论) 对互联网的暴露面想要收敛对外暴露面的风险,就必须先知道自己的暴露面范围。以下是企业常见的暴露面的分类,…

信息论基础 | 第五章 编码理论

2025-11-10 11:02:47 星期一 5.1 关于编码的例子 首先给出定义 定义 关于随机变量 \(X\) 的信源编码 \(C\) 是从 \(X\) 的取值空间 \(\mathcal{X}\) 到 \(\mathcal{D}^*\) 的一个映射,其中 \(\mathcal{D}^*\) 表示 \(…

2025年高端员工工作服定做厂家权威推荐榜单:高端工服/高端劳保工作服/高端夏季工作服源头厂家精选

一套高品质的工作服,已成为企业形象展示、员工安全保障与团队凝聚力提升的重要载体。 据行业数据显示,2025年中国职业装市场规模预计达到2300亿元,年均复合增长率保持在8%-10%左右。在消费升级和技术进步的双重推动…

2025 年 11 月桥架厂家推荐排行榜,电缆桥架,梯级式桥架,快速连接桥架,托盘式桥架,不锈钢桥架,深联桥架公司推荐

2025 年 11 月桥架厂家推荐排行榜:电缆桥架、梯级式桥架、快速连接桥架、托盘式桥架、不锈钢桥架、深联桥架公司推荐 行业背景与发展趋势 桥架作为现代建筑电气布线系统的重要组成部分,在电力、通信、数据中心等领域…

在跳板机的远程桌面中输入ctrl+alt+end

在跳板机的远程桌面中输入ctrl+alt+end在终端服务器中cmd中输入osk打开系统键盘(不能打开屏幕键盘,测试发现没用) 点击ctrl+alt+del 组合键

十类图片深度学习提升准确率(0.9317) - 实践

十类图片深度学习提升准确率(0.9317) - 实践2025-11-12 10:27 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: …

实现文件外发管控怎么做的全面指南

在企业进行文件外发管理时,全面的管控措施能有效提升信息安全与运营效率。首先,细化权限管理是保护敏感信息的基石,通过明确的权限划分,可以有效控制谁能够访问和外发特定文件。其次,规范的审批流程确保每一份文件…

2025CSP-S组 T2 部分分做法

S组 T2 部分分分析很重要,如果全部分类写出,可以得72分,虽没想出最后正解,但也很高了 想得到满分,就要注意到n比m小, k<=10, 也很小。这两个就是瓶颈。 P14362 [CSP-S 2025] 道路修复 / road(官方数据) 【解…

2025 年 11 月管道厂家推荐排行榜,PVC管道,PPR管道,市政管道,民用管道,深塑管道,HDPE波纹管道公司推荐

2025年11月管道厂家推荐排行榜:PVC管道、PPR管道、市政管道、民用管道、深塑管道、HDPE波纹管道公司推荐 行业背景与发展趋势 管道系统作为基础设施建设的重要组成部分,在城镇化进程和建筑工程领域发挥着关键作用。随…