10.C++设计模式-代理模式

一、什么是代理模式

代理模式是一种结构型设计模式,它为另一个对象提供一个替身或占位符以控制对这个对象的访问。代理模式在不修改原始对象的基础上,通过引入代理对象来扩展或控制对原始对象的访问。

二、核心角色

持有
<<interface>>
Subject
+request()
RealSubject
+request()
Proxy
-realSubject: RealSubject
+request()
+checkAccess()
+logAccess()

角色说明:

  • Subject(抽象主题):定义真实对象和代理的共同接口
  • RealSubject(真实主题):真正的业务逻辑对象
  • Proxy(代理):持有对真实对象的引用,控制访问

三、代理模式分类与应用场景

1. 虚拟代理

场景 :延迟加载大对象,如高清图片、大文件等
示例:图片浏览器中的缩略图代理

2. 保护代理

场景 :控制访问权限,不同用户不同权限
示例:文档系统,管理员可读写,普通用户只读

3. 远程代理

场景 :隐藏对象在不同地址空间的事实
示例:RPC调用、Web服务代理

4. 智能引用代理

场景 :在访问对象时添加额外操作
示例:引用计数、日志记录、性能监控

四、C++代码示例

示例1:虚拟代理(图片加载)
cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

// 抽象主题
class Image {
public:
    virtual ~Image() = default;
    virtual void display() = 0;
};

// 真实主题:大尺寸图片
class HighResolutionImage : public Image {
private:
    std::string filename;
    
    void loadImageFromDisk() {
        std::cout << "正在从磁盘加载高清图片: " << filename << " (耗时3秒)...\n";
        // 模拟耗时加载
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    
public:
    HighResolutionImage(const std::string& name) : filename(name) {
        loadImageFromDisk();
    }
    
    void display() override {
        std::cout << "显示高清图片: " << filename << "\n";
    }
};

// 代理:图片代理
class ImageProxy : public Image {
private:
    std::string filename;
    std::unique_ptr<HighResolutionImage> realImage;
    
public:
    ImageProxy(const std::string& name) : filename(name), realImage(nullptr) {}
    
    void display() override {
        // 延迟加载:只有在真正需要时才创建真实对象
        if (!realImage) {
            realImage = std::make_unique<HighResolutionImage>(filename);
        }
        realImage->display();
    }
};

// 使用示例
int main() {
    // 创建代理对象(不会立即加载图片)
    std::unique_ptr<Image> image = std::make_unique<ImageProxy>("photo.jpg");
    
    std::cout << "图片对象已创建,但尚未加载到内存\n";
    std::cout << "用户滚动到图片可见区域...\n";
    
    // 真正需要显示时才加载
    image->display();
    
    return 0;
}
示例2:保护代理(权限控制)
cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

// 抽象主题
class Document {
public:
    virtual ~Document() = default;
    virtual void read() = 0;
    virtual void write(const std::string& content) = 0;
};

// 真实主题
class RealDocument : public Document {
private:
    std::string content;
    std::string title;
    
public:
    RealDocument(const std::string& t) : title(t), content("原始内容") {}
    
    void read() override {
        std::cout << "阅读文档《" << title << "》\n内容: " << content << "\n";
    }
    
    void write(const std::string& newContent) override {
        content = newContent;
        std::cout << "文档已更新\n";
    }
};

// 代理:带权限控制的文档代理
class DocumentProxy : public Document {
private:
    std::unique_ptr<RealDocument> realDoc;
    std::string userRole;
    
    bool hasReadPermission() {
        return true; // 所有人可读
    }
    
    bool hasWritePermission() {
        return userRole == "admin" || userRole == "editor";
    }
    
public:
    DocumentProxy(const std::string& title, const std::string& role) 
        : realDoc(std::make_unique<RealDocument>(title)), userRole(role) {}
    
    void read() override {
        if (hasReadPermission()) {
            realDoc->read();
        } else {
            std::cout << "权限不足:无法读取文档\n";
        }
    }
    
    void write(const std::string& content) override {
        if (hasWritePermission()) {
            realDoc->write(content);
        } else {
            std::cout << "权限不足:需要管理员或编辑权限才能写入\n";
        }
    }
};

// 使用示例
int main() {
    std::cout << "=== 普通用户访问 ===\n";
    auto userDoc = std::make_unique<DocumentProxy>("设计模式", "user");
    userDoc->read();      // 成功
    userDoc->write("新内容"); // 失败
    
    std::cout << "\n=== 管理员访问 ===\n";
    auto adminDoc = std::make_unique<DocumentProxy>("设计模式", "admin");
    adminDoc->read();      // 成功
    adminDoc->write("专业内容"); // 成功
    
    return 0;
}
示例3:智能引用代理(日志记录)
cpp 复制代码
#include <iostream>
#include <chrono>
#include <memory>

// 抽象主题
class Calculator {
public:
    virtual ~Calculator() = default;
    virtual int add(int a, int b) = 0;
    virtual int multiply(int a, int b) = 0;
};

// 真实主题
class RealCalculator : public Calculator {
public:
    int add(int a, int b) override {
        return a + b;
    }
    
    int multiply(int a, int b) override {
        return a * b;
    }
};

// 代理:带日志和性能监控的计算器
class CalculatorProxy : public Calculator {
private:
    std::unique_ptr<RealCalculator> realCalc;
    
    void logOperation(const std::string& op, int a, int b, int result, double duration) {
        std::cout << "[LOG] " << op << "(" << a << ", " << b 
                  << ") = " << result << " | 耗时: " << duration << "ms\n";
    }
    
public:
    CalculatorProxy() : realCalc(std::make_unique<RealCalculator>()) {}
    
    int add(int a, int b) override {
        auto start = std::chrono::high_resolution_clock::now();
        
        // 前置处理
        std::cout << "准备执行加法运算...\n";
        
        // 调用真实对象
        int result = realCalc->add(a, b);
        
        // 后置处理
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration<double, std::milli>(end - start).count();
        
        logOperation("add", a, b, result, duration);
        
        return result;
    }
    
    int multiply(int a, int b) override {
        auto start = std::chrono::high_resolution_clock::now();
        
        std::cout << "准备执行乘法运算...\n";
        int result = realCalc->multiply(a, b);
        
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration<double, std::milli>(end - start).count();
        
        logOperation("multiply", a, b, result, duration);
        
        return result;
    }
};

// 使用示例
int main() {
    auto calc = std::make_unique<CalculatorProxy>();
    
    int sum = calc->add(10, 20);
    std::cout << "结果: " << sum << "\n\n";
    
    int product = calc->multiply(5, 6);
    std::cout << "结果: " << product << "\n";
    
    return 0;
}

五、代理模式优缺点

缺点
增加系统复杂度
处理速度变慢
多重代理复杂
优点
职责清晰
高扩展性
智能化
延迟加载

优点:

  • 职责清晰:真实对象专注业务,代理负责辅助功能
  • 高扩展性:可以在不修改真实对象的情况下增加功能
  • 智能化:可以实现延迟加载、访问控制等智能行为
  • 解耦合:客户端与真实对象解耦

缺点:

  • 增加了系统复杂性
  • 多一层代理可能影响处理速度
  • 多重代理可能导致系统复杂难以维护

六、代理模式 vs 装饰器模式

对比项 代理模式 装饰器模式
目的 控制访问 增强功能
关系 编译时确定 运行时动态组合
创建 代理知道真实对象 客户端控制装饰顺序
重点 控制访问权限 添加新行为

七、实际应用场景

  1. 智能指针std::shared_ptr 是典型的智能引用代理
  2. 延迟加载框架:ORM框架中的懒加载
  3. AOP编程:Spring框架的AOP代理
  4. 网络代理:HTTP代理、反向代理
  5. 缓存代理:缓存计算结果

代理模式是一个非常实用的设计模式,在框架设计、权限控制、性能优化等场景中都有广泛应用。

相关推荐
郝学胜-神的一滴1 小时前
CMake 010 :一步到位链接静态库
开发语言·c++·qt·程序人生·系统架构·cmake
小则又沐风a1 小时前
C++继承
开发语言·c++
雪度娃娃1 小时前
转向现代C++——在创建对象时注意区分()和{}
开发语言·c++
Tisfy1 小时前
VSCode Docker(Code Server)首次调试C++长时间下载debuginfo问题
c++·vscode·docker
读书札记20221 小时前
C++ switch..case语句中变量跨域问题探讨及解决方法
开发语言·c++
努力努力再努力wz1 小时前
【Redis入门系列】Redis基础命令详解:从客户端连接到数据读写、key 管理与过期机制
c语言·开发语言·数据结构·数据库·c++·redis·缓存
Peter·Pan爱编程1 小时前
输入输出:iostream 为什么不是 printf 的替代品
c++·输入输出·c++基础·iostream
代码村新手2 小时前
C++-模板进阶
开发语言·c++
Shadow(⊙o⊙)2 小时前
qt中自定义槽函数 内部继承逻辑、GUI+CLI协同1.0
开发语言·前端·c++·qt