【设计模式】代理模式(Proxy Pattern)详解
代理模式(Proxy Pattern)详解
一、代理模式的概念
代理模式(Proxy Pattern)是一种结构型设计模式,它通过一个代理对象来控制对另一个对象的访问。
核心思想:
- 代理对象和被代理对象实现相同的接口。
- 代理对象在调用目标对象前后增加额外的功能(如日志、权限控制、缓存、延迟加载等)。
- 客户端只和代理对象交互,不直接访问目标对象,从而降低耦合,提高扩展性。
二、代理模式的作用
1. 控制访问权限:
- 例如,用户未登录时拦截请求,避免访问敏感资源。
2. 记录日志:
- 例如,记录用户的 API 调用信息,便于追踪。
3. 提供缓存:
- 例如,避免重复请求数据库,提高性能。
4. 远程代理:
- 例如,前端调用后端 API,代理请求数据。
5. 延迟初始化(懒加载):
- 例如,对象创建成本高时,先用代理对象占位,等需要时再创建。
三、代理模式的分类
代理模式主要分为以下几种类型:
类型 | 特点 | 示例 |
---|---|---|
远程代理(Remote Proxy) | 代理远程对象 | 前端调用后端 API,如 axios 代理请求 |
虚拟代理(Virtual Proxy) | 延迟加载,按需创建 | Vue 懒加载图片 |
保护代理(Protection Proxy) | 控制访问权限 | 用户权限控制,未登录时拦截请求 |
缓存代理(Cache Proxy) | 缓存数据,避免重复计算 | Redis 数据缓存 |
智能引用代理(Smart Reference Proxy) | 统计对象引用次数,自动释放 | Vue3 Proxy 监听对象变化 |
四、代理模式的代码实现
1. JavaScript 经典示例
🔹 直接访问 vs 代理访问
class RealSubject {
request() {
console.log("RealSubject: Handling request.");
}
}
class Proxy {
constructor(realSubject) {
this.realSubject = realSubject;
}
request() {
console.log("Proxy: Checking access before forwarding the request.");
this.realSubject.request();
console.log("Proxy: Logging the request after execution.");
}
}
// 使用代理
const realSubject = new RealSubject();
const proxy = new Proxy(realSubject);
proxy.request();
🔹 输出
Proxy: Checking access before forwarding the request.
RealSubject: Handling request.
Proxy: Logging the request after execution.
🔹 解释
Proxy
代理RealSubject
,在调用request()
方法前后添加额外的逻辑(如权限检查和日志记录)。- 客户端只和代理交互,不直接访问真实对象。
2. 远程代理(API 请求代理)
场景:
- 代理前端 API 请求,自动添加
Authorization
头,避免手动传递token
。
class APIProxy {
constructor(baseURL) {
this.baseURL = baseURL;
}
async request(endpoint, options = {}) {
// 自动添加身份认证 Token
options.headers = {
...options.headers,
Authorization: `Bearer ${localStorage.getItem("token")}`
};
console.log(`Requesting: ${this.baseURL}${endpoint}`);
const response = await fetch(`${this.baseURL}${endpoint}`, options);
return response.json();
}
}
// 使用代理请求 API
const api = new APIProxy("https://api.example.com");
api.request("/users").then(data => console.log(data));
🔹 代理的作用
- 拦截 API 请求,自动添加
Authorization
头。 - 减少重复代码,开发者无需手动添加
token
。
3. 虚拟代理(懒加载图片)
场景:
- 图片未加载时先显示占位符,等图片加载完成后再替换。
class ImageProxy {
constructor(realImageURL) {
this.realImageURL = realImageURL;
this.imgElement = document.createElement("img");
this.imgElement.src = "placeholder.jpg"; // 先显示占位图
// 模拟网络请求加载真实图片
setTimeout(() => {
this.imgElement.src = this.realImageURL;
}, 2000);
}
getImageElement() {
return this.imgElement;
}
}
// 使用代理
const proxyImage = new ImageProxy("real-image.jpg");
document.body.appendChild(proxyImage.getImageElement());
🔹 代理的作用
- 图片未加载时先显示占位符,等加载完成后自动替换。
- 减少页面加载阻塞,提高用户体验。
4. 保护代理(权限控制)
场景:
- 用户未登录时,拦截敏感操作。
class User {
constructor(name, role) {
this.name = name;
this.role = role;
}
}
class AdminAccessProxy {
constructor(user) {
this.user = user;
}
deleteData() {
if (this.user.role !== "admin") {
console.log("Access Denied: Only admin can delete data.");
return;
}
console.log("Data deleted successfully.");
}
}
// 创建用户
const normalUser = new User("John", "guest");
const adminUser = new User("Alice", "admin");
// 代理对象
const proxy1 = new AdminAccessProxy(normalUser);
proxy1.deleteData(); // 拒绝访问
const proxy2 = new AdminAccessProxy(adminUser);
proxy2.deleteData(); // 成功删除
🔹 代理的作用
- 控制权限:只有
admin
用户才能执行删除操作。 - 安全性提升,防止未授权用户访问敏感功能。
五、代理模式 vs 装饰器模式
对比项 | 代理模式(Proxy) | 装饰器模式(Decorator) |
---|---|---|
核心作用 | 控制访问,拦截请求 | 动态增强对象功能 |
是否继承原对象 | 通常实现相同接口 | 直接增强已有对象 |
典型应用 | API 请求代理、权限控制、缓存 | Vue3 reactive() 、日志增强 |
对象的创建 | 代理对象可以创建或管理真实对象 | 直接包装对象,增强功能 |
六、代理模式的优缺点
✅ 优点
✔ 解耦客户端和目标对象,增强扩展性。
✔ 权限控制(如 API 访问权限)。
✔ 延迟初始化,提高性能(如图片懒加载)。
✔ 日志、缓存、监控,增强功能。
❌ 缺点
❌ 增加系统复杂度,需要额外的代理类。
❌ 可能带来性能开销(如远程代理涉及网络通信)。
七、总结
- 代理模式通过一个代理对象控制对目标对象的访问,可以在访问前后添加额外逻辑。
- 代理模式适用于:
- API 请求代理(自动添加
token
)。 - 懒加载(图片、数据)。
- 权限控制(用户角色判断)。
- 缓存代理(避免重复计算)。
- API 请求代理(自动添加
- 常见的代理模式:
- 远程代理(API 请求代理)。
- 虚拟代理(懒加载)。
- 保护代理(权限控制)。
🚀 代理模式是前端、后端、运维等多个领域的重要设计模式,合理使用可提高代码质量!