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

代理模式及优化

代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过创建一个代理对象来控制对另一个对象(称为真实对象或被代理对象)的访问。代理对象充当客户端和真实对象之间的中介,客户端通过代理对象间接访问真实对象,从而可以在不改变真实对象的前提下添加额外的功能或控制逻辑。

一、介绍

核心概念
  1. 主题接口(Subject Interface)
    • 定义真实对象和代理对象的共同接口,确保客户端可以统一地使用它们。
    • 客户端通过此接口与代理和真实对象交互。
  2. 真实主题(Real Subject)
    • 实现主题接口的具体对象,提供实际的业务功能。
    • 通常是开销较大或需要特殊处理的对象。
  3. 代理(Proxy)
    • 实现与真实主题相同的接口,持有对真实主题的引用。
    • 控制对真实主题的访问,并可以在调用前后添加额外逻辑。
优点
  1. 解耦客户端与真实对象
    • 客户端无需知道真实对象的具体实现,降低耦合度
  2. 增强安全性
    • 通过代理控制访问权限,保护敏感资源
  3. 提高性能
    • 延迟加载和缓存机制优化资源利用
  4. 简化复杂系统
    • 隐藏网络通信、资源管理等复杂细节
  5. 符合开闭原则
    • 可以在不修改真实对象的情况下添加新的代理功能
缺点
  1. 增加系统复杂度
    • 多层代理或复杂代理逻辑可能导致代码难以理解
  2. 性能开销
    • 代理调用会引入额外的处理步骤,可能影响性能
  3. 可能导致设计过度
    • 如果不需要额外控制或功能,使用代理会显得冗余
代理模式的使用时机
  1. 延迟初始化(虚拟代理)
    • 当创建开销大的对象时,通过代理延迟到真正需要时再创建
    • 如示例中的图片加载,首次访问时才加载资源
  2. 访问控制(保护代理)
    • 限制对真实对象的访问权限
    • 例如:验证用户权限后才允许访问敏感资源
  3. 远程对象代理(远程代理)
    • 为位于不同地址空间的对象提供本地接口
    • 如分布式系统中,代理负责网络通信细节
  4. 操作监控(智能引用代理)
    • 在访问对象时附加额外操作
    • 例如:引用计数、缓存、日志记录等
  5. 资源优化(缓存代理)
    • 缓存频繁访问的对象结果
    • 如数据库查询结果的临时缓存

二、实现

#include <iostream>
#include <string>// 主题接口
class Image {
public:virtual void display() const = 0;virtual ~Image() = default;
};// 真实主题
class RealImage : public Image {
private:std::string filename;public:explicit RealImage(const std::string& filename) : filename(filename) {loadFromDisk();}void display() const override {std::cout << "Displaying image: " << filename << std::endl;}private:void loadFromDisk() const {std::cout << "Loading image: " << filename << std::endl;}
};// 代理
class ProxyImage : public Image {
private:std::string filename;mutable RealImage* realImage = nullptr;public:explicit ProxyImage(const std::string& filename) : filename(filename) {}~ProxyImage() override {delete realImage;}void display() const override {if (!realImage) {realImage = new RealImage(filename);}realImage->display();}
};// 客户端代码
int main() {Image* image = new ProxyImage("test.jpg");// 第一次调用,会加载并显示image->display();std::cout << std::endl;// 第二次调用,直接显示(已加载)image->display();delete image;return 0;
}
实现注意事项
  1. 接口一致性
    • 代理必须实现与真实对象相同的接口,确保透明替换
  2. 生命周期管理
    • 代理需要正确管理真实对象的生命周期,避免内存泄漏
  3. 线程安全
    • 在多线程环境中,代理需要处理好并发访问问题
  4. 避免过度使用
    • 仅在确实需要控制访问或增强功能时使用代理模式
常见应用场景
  1. 远程代理(Remote Proxy)

    • 为位于不同地址空间的对象提供本地接口
    • 例如:分布式系统中的远程方法调用(RMI)、Web服务客户端代理
  2. 虚拟代理(Virtual Proxy)

    • 延迟创建开销大的对象,直到真正需要时才实例化
    • 例如:图片懒加载、大型文档的部分内容加载
  3. 保护代理(Protection Proxy)

    • 控制对敏感对象的访问权限
    • 例如:基于角色的访问控制、操作系统文件权限管理
  4. 智能引用代理(Smart Reference Proxy)

    • 在访问对象时附加额外操作,如引用计数、缓存、资源释放等
    • 例如:智能指针、COM组件的生命周期管理
  5. 缓存代理(Caching Proxy)

    • 缓存频繁访问的对象结果,提高性能
    • 例如:数据库查询结果缓存、CDN缓存静态资源

三、优化

  1. 内存管理:使用智能指针避免内存泄漏
  2. 线程安全:通过双重检查锁定支持多线程
  3. 功能扩展
    • 缓存机制减少重复加载
    • 日志记录增强可观测性
    • 访问控制提升安全性
  4. 灵活性
    • 工厂模式解耦对象创建
    • 代理可组合使用
  5. 性能优化
    • 延迟加载减少初始开销
    • 缓存复用已有资源

用户会话管理系统

#include <iostream>
#include <string>
#include <memory>
#include <unordered_map>
#include <mutex>
#include <chrono>
#include <vector>// 会话管理系统
class Session {
public:virtual std::string getRole() const = 0;virtual ~Session() = default;
};class GuestSession : public Session {
public:std::string getRole() const override { return "guest"; }
};class AdminSession : public Session {
public:std::string getRole() const override { return "admin"; }
};class SessionManager {
private:static SessionManager* instance;std::unique_ptr<Session> currentSession;SessionManager() : currentSession(std::make_unique<GuestSession>()) {}SessionManager(const SessionManager&) = delete;SessionManager& operator=(const SessionManager&) = delete;public:static SessionManager* getInstance() {if (!instance) {instance = new SessionManager();}return instance;}void loginAsAdmin() {std::cout << "Logging in as admin..." << std::endl;currentSession = std::make_unique<AdminSession>();}void logout() {std::cout << "Logging out..." << std::endl;currentSession = std::make_unique<GuestSession>();}const Session& getSession() const {return *currentSession;}
};
SessionManager* SessionManager::instance = nullptr;

代理模式优化

// 主题接口
class Image {
public:virtual void display() const = 0;virtual ~Image() = default;
};// 真实主题
class RealImage : public Image {
private:std::string filename;public:explicit RealImage(const std::string& filename) : filename(filename) {loadFromDisk();}void display() const override {std::cout << "Displaying image: " << filename << std::endl;}const std::string& getFilename() const { return filename; }private:void loadFromDisk() const {std::cout << "Loading image: " << filename << std::endl;}
};// 代理实现
// 延迟加载代理
class ProxyImage : public Image {
private:std::string filename;mutable std::unique_ptr<RealImage> realImage;public:explicit ProxyImage(const std::string& filename) : filename(filename) {}void display() const override {if (!realImage) {std::cout << "Creating real image for " << filename << std::endl;realImage = std::make_unique<RealImage>(filename);}realImage->display();}
};// 缓存代理
class CachedProxyImage : public Image {
private:std::string filename;mutable std::shared_ptr<RealImage> realImage;static std::unordered_map<std::string, std::weak_ptr<RealImage>> cache;static std::mutex cacheMutex;public:explicit CachedProxyImage(const std::string& filename) : filename(filename) {}void display() const override {std::lock_guard<std::mutex> lock(cacheMutex);auto it = cache.find(filename);if (it != cache.end() && !it->second.expired()) {std::cout << "Using cached image: " << filename << std::endl;realImage = it->second.lock();} else {std::cout << "Caching new image: " << filename << std::endl;realImage = std::make_shared<RealImage>(filename);cache[filename] = realImage;}realImage->display();}
};std::unordered_map<std::string, std::weak_ptr<RealImage>> CachedProxyImage::cache;
std::mutex CachedProxyImage::cacheMutex;// 访问控制代理
class AuthProxy : public Image {
private:std::unique_ptr<Image> target;std::string requiredRole;public:AuthProxy(std::unique_ptr<Image> img, const std::string& role) : target(std::move(img)), requiredRole(role) {}void display() const override {if (checkAccess()) {target->display();} else {std::cout << "Access denied: Requires role '" << requiredRole << "', current role is '" << SessionManager::getInstance()->getSession().getRole() << "'" << std::endl;}}private:bool checkAccess() const {const auto& role = SessionManager::getInstance()->getSession().getRole();return role == requiredRole || role == "admin"; // 管理员可以访问所有资源}
};// 日志代理
class LoggingProxy : public Image {
private:std::unique_ptr<Image> target;public:explicit LoggingProxy(std::unique_ptr<Image> img) : target(std::move(img)) {}void display() const override {std::cout << "[LOG] Display request for " << getFilename() << std::endl;auto start = std::chrono::high_resolution_clock::now();target->display();auto end = std::chrono::high_resolution_clock::now();std::cout << "[LOG] Display completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()<< "ms" << std::endl;}private:std::string getFilename() const {if (auto real = dynamic_cast<RealImage*>(target.get())) {return real->getFilename();}return "unknown";}
};// 工厂类
class ImageFactory {
public:static std::shared_ptr<Image> createProtectedImage(const std::string& filename, const std::string& role) {return std::make_shared<LoggingProxy>(std::make_unique<AuthProxy>(std::make_unique<CachedProxyImage>(filename),role));}
};// 客户端代码
int main() {// 创建需要管理员权限的图片代理auto image = ImageFactory::createProtectedImage("sensitive.jpg", "admin");// 尝试以访客身份访问(会被拒绝)std::cout << "=== Attempting to access as guest ===" << std::endl;image->display();// 登录为管理员SessionManager::getInstance()->loginAsAdmin();// 再次尝试访问(成功)std::cout << "\n=== Logged in as admin, attempting access ===" << std::endl;image->display();// 再次请求同一图片(使用缓存)std::cout << "\n=== Requesting same image again ===" << std::endl;image->display();// 创建普通用户可见的图片std::cout << "\n=== Creating user-level image ===" << std::endl;auto userImage = ImageFactory::createProtectedImage("public.jpg", "user");// 管理员可以访问用户级资源userImage->display();// 登出SessionManager::getInstance()->logout();// 尝试再次访问(被拒绝)std::cout << "\n=== Logged out, attempting access again ===" << std::endl;image->display();userImage->display();return 0;
}
优化项
1. 内存管理优化(使用智能指针)
#include <memory>class ProxyImage : public Image {
private:std::string filename;mutable std::unique_ptr<RealImage> realImage; // 智能指针自动管理内存public:explicit ProxyImage(const std::string& filename) : filename(filename) {}void display() const override {if (!realImage) {realImage = std::make_unique<RealImage>(filename);}realImage->display();}
};

优点:避免内存泄漏,无需手动管理RealImage生命周期

2. 接口抽象与工厂模式
// 工厂类创建代理
class ImageFactory {
public:static std::shared_ptr<Image> createImage(const std::string& filename) {return std::make_shared<ProxyImage>(filename);}
};// 客户端使用
auto image = ImageFactory::createImage("test.jpg");

优点:解耦对象创建逻辑,支持未来扩展其他代理类型

3. 多线程安全(双重检查锁定)
void display() const override {if (!realImage) {std::lock_guard<std::mutex> lock(mutex); // 加锁if (!realImage) { // 双重检查realImage = std::make_unique<RealImage>(filename);}}realImage->display();
}

优点:在多线程环境下保证RealImage只被创建一次

4. 缓存机制(扩展代理功能)
class CachedProxyImage : public Image {
private:std::string filename;mutable std::shared_ptr<RealImage> realImage;static std::unordered_map<std::string, std::weak_ptr<RealImage>> cache;static std::mutex cacheMutex;public:explicit CachedProxyImage(const std::string& filename) : filename(filename) {}void display() const override {std::lock_guard<std::mutex> lock(cacheMutex);// 检查缓存auto it = cache.find(filename);if (it != cache.end() && !it->second.expired()) {realImage = it->second.lock();} else {realImage = std::make_shared<RealImage>(filename);cache[filename] = realImage;}realImage->display();}
};

优点:相同文件只加载一次,节省资源

5. 延迟加载策略(参数化控制)
class ConfigurableProxy : public Image {
private:std::string filename;std::unique_ptr<RealImage> realImage;bool lazyLoad;public:explicit ConfigurableProxy(const std::string& filename, bool lazy = true) : filename(filename), lazyLoad(lazy) {}void display() const override {if (!realImage && lazyLoad) {realImage = std::make_unique<RealImage>(filename);}if (realImage) realImage->display();else std::cout << "Image not loaded" << std::endl;}void forceLoad() { // 提供显式加载接口if (!realImage) {realImage = std::make_unique<RealImage>(filename);}}
};

优点:支持灵活的加载策略配置

6. 日志记录(横切关注点)
class LoggingProxy : public Image {
private:std::unique_ptr<Image> target;public:explicit LoggingProxy(std::unique_ptr<Image> img) : target(std::move(img)) {}void display() const override {std::cout << "[LOG] Display request for " << getFilename() << std::endl;auto start = std::chrono::high_resolution_clock::now();target->display();auto end = std::chrono::high_resolution_clock::now();std::cout << "[LOG] Display completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()<< "ms" << std::endl;}private:std::string getFilename() const {// 通过dynamic_cast尝试获取文件名(需要在RealImage中暴露接口)if (auto real = dynamic_cast<RealImage*>(target.get())) {return real->getFilename();}return "unknown";}
};

优点:非侵入式添加日志功能

7. 访问控制(保护代理)
class AuthProxy : public Image {
private:std::unique_ptr<Image> target;std::string requiredRole;public:AuthProxy(std::unique_ptr<Image> img, const std::string& role) : target(std::move(img)), requiredRole(role) {}void display() const override {if (checkAccess()) {target->display();} else {std::cout << "Access denied: Requires role " << requiredRole << std::endl;}}private:bool checkAccess() const {// 实际实现中会检查当前用户角色// 这里简化为硬编码检查return UserSession::getCurrentRole() == requiredRole;}
};

优点:实现细粒度的访问控制

8. 组合多种代理
// 客户端可以组合使用多种代理
auto image = std::make_unique<LoggingProxy>(std::make_unique<AuthProxy>(std::make_unique<ProxyImage>("secret.jpg"),"admin")
);image->display(); // 先验证权限,再记录日志,最后显示图片

优点:灵活组合不同功能的代理

四、与其他模式的区别

  1. 与装饰器模式的区别

    • 代理模式:重点在于控制对象的访问,客户端通常不知道真实对象的存在
    • 装饰器模式:重点在于动态增强对象的功能,客户端直接与装饰器交互
  2. 与适配器模式的区别

    • 代理模式:保持接口不变,提供相同功能但增加控制逻辑
    • 适配器模式:改变接口以适配不同的客户端需求
http://www.dtcms.com/a/286751.html

相关文章:

  • 代码随想录day38dp6
  • STM32-第七节-TIM定时器-3(输入捕获)
  • 全排列 II
  • C#通过HslCommunication连接西门子PLC1200,并防止数据跳动的通用方法
  • 反序列化漏洞2-魔术方法介绍与演示
  • 怎么自己搭建云手机
  • http与https的主要区别是什么?
  • java数据类型
  • 锂电池无线充电电路设计
  • 零碳园区势在必行!安科瑞EMS3.0助力园区低碳智慧升级
  • Excel导出实战:从入门到精通 - 构建专业级数据报表的完整指南
  • 如何使用 Jackson 处理 YAML
  • AE电源MDX 5K 10K 15K 20K 25K 30K手侧操作使用说明
  • 拉普拉斯方程傅里叶积分解法
  • @Primary 是做什么的?
  • CAD 约束求解:核心技术原理、流程及主流框架快速解析
  • A33-vstar笔记及资料分享:搭建交叉编译环境
  • 动态规划 + DFS + 记忆化!Swift 解 LeetCode 329 的实战笔记
  • 实战指南|智慧无人机安防系统搭建全流程解析
  • 记录DataGrip 2025.1.3破解失败后,无法重启问题修复
  • centos7安装MySQL8.4手册
  • Hive数据仓库工具
  • 甲状腺结节TI-RADS分类的多目标分类头任务深度学习模型评估报告
  • go语言学习之包
  • 新书推介 | 吉林大学出版教材《汽车智能辅助驾驶系统技术》,国产仿真工具链GCKontrol-GCAir教学应用
  • Python_2
  • math.h函数
  • 弱网测试
  • 跨域问题及解决方案
  • ChatGPT Agent:统一端到端Agentic模型的技术革新与行业影响