【C++设计模式】第十二篇:代理模式(Proxy)

注意:复现代码时,确保 VS2022 使用 C++17/20 标准以支持现代特性。

控制对象访问的智能中介


1. 模式定义与用途

核心思想

  • 代理模式:为其他对象提供一种**代理(替代品)**​以控制对这个对象的访问。
  • 关键用途
    ​1.延迟加载:仅在需要时创建开销大的对象(如图像懒加载)。
    ​2.访问控制:校验权限或过滤请求(如敏感操作代理)。
    ​3.远程服务:本地代理隐藏网络通信细节(如RPC调用)。

经典场景

  • 虚拟代理:大图加载前的占位符。
  • 保护代理:接口访问权限验证。
  • 日志代理:记录操作历史或性能指标。

2. 模式结构解析

UML类图

+---------------------+          +---------------------+  
|       Subject       |          |        Proxy        |  
+---------------------+          +---------------------+  
| + request(): void   |<|---- ---| - realSubject: RealSubject |  
+---------------------+          | + request(): void   |  
          ^                      +---------------------+  
          |                                ^  
          |                                |  
+---------------------+          +---------------------+  
|    RealSubject      |          |   Client            |  
+---------------------+          +---------------------+  
| + request()         |  
+---------------------+  

角色说明

  1. Subject:抽象接口,定义客户端和代理的共同操作(如request())。
  2. RealSubject:真实对象,完成核心业务逻辑。
  3. Proxy:代理类,控制对RealSubject的访问,可附加额外逻辑。

3. 现代C++实现示例

场景1:虚拟代理(图像懒加载)​

#include <iostream>  
#include <memory>  
#include <string>  

// 抽象图像接口  
class Image {  
public:  
    virtual ~Image() = default;  
    virtual void display() = 0;  
};  

// 真实对象:高分辨率图像(加载开销大)  
class HighResImage : public Image {  
public:  
    HighResImage(const std::string& path) : path_(path) {  
        loadFromDisk();  
    }  

    void display() override {  
        std::cout << "显示图像: " << path_ << "\n";  
    }  

private:  
    void loadFromDisk() {  
        std::cout << "从磁盘加载大图: " << path_ << "(耗时操作)\n";  
    }  
    std::string path_;  
};  

// 代理:延迟加载图像  
class LazyImageProxy : public Image {  
public:  
    LazyImageProxy(const std::string& path) : path_(path) {}  

    void display() override {  
        if (!realImage_) {  
            realImage_ = std::make_unique<HighResImage>(path_);  
        }  
        realImage_->display();  
    }  

private:  
    std::unique_ptr<Image> realImage_;  
    std::string path_;  
};  

// 客户端代码  
int main() {  
    LazyImageProxy proxy("wallpaper.jpg");  
    // 图像未加载  
    proxy.display();  // 首次调用触发加载  
}  
/* 输出:  
从磁盘加载大图: wallpaper.jpg(耗时操作)  
显示图像: wallpaper.jpg  
*/  

场景2:保护代理(权限验证)​

#include <unordered_map>  

// 用户权限系统  
class User {  
public:  
    User(const std::string& role) : role_(role) {}  
    const std::string& getRole() const { return role_; }  

private:  
    std::string role_;  
};  

// 敏感操作接口  
class Database {  
public:  
    virtual void executeQuery(const std::string& query, const User& user) = 0;  
};  

// 真实数据库  
class RealDatabase : public Database {  
public:  
    void executeQuery(const std::string& query, const User& user) override {  
        std::cout << "执行查询: " << query << "\n";  
    }  
};  

// 保护代理:检查权限  
class SecureDatabaseProxy : public Database {  
public:  
    SecureDatabaseProxy() : realDb_(std::make_unique<RealDatabase>()) {}  

    void executeQuery(const std::string& query, const User& user) override {  
        if (user.getRole() == "admin") {  
            realDb_->executeQuery(query, user);  
        } else {  
            std::cout << "拒绝访问:用户权限不足\n";  
        }  
    }  

private:  
    std::unique_ptr<Database> realDb_;  
};  

// 使用示例  
User admin("admin");  
User guest("guest");  
SecureDatabaseProxy proxy;  

proxy.executeQuery("DELETE * FROM users", admin);  // 允许  
proxy.executeQuery("SELECT * FROM logs", guest);    // 拒绝  

4. 应用场景示例

场景1:远程服务代理(RPC客户端)

// 远程服务接口(客户端存根)  
class RemoteService {  
public:  
    virtual std::string fetchData(int id) = 0;  
};  

// 真实服务(模拟网络调用)  
class RemoteServiceImpl : public RemoteService {  
public:  
    std::string fetchData(int id) override {  
        // 模拟网络请求  
        return "Data for ID " + std::to_string(id);  
    }  
};  

// 本地代理(缓存与重试逻辑)  
class RemoteServiceProxy : public RemoteService {  
public:  
    RemoteServiceProxy() : service_(std::make_unique<RemoteServiceImpl>()) {}  

    std::string fetchData(int id) override {  
        if (cache_.find(id) != cache_.end()) {  
            return cache_[id];  
        }  
        // 模拟重试机制  
        for (int i = 0; i < 3; ++i) {  
            try {  
                auto data = service_->fetchData(id);  
                cache_[id] = data;  
                return data;  
            } catch (const std::exception& e) {  
                std::cout << "第 " << i + 1 << " 次重试...\n";  
            }  
        }  
        throw std::runtime_error("远程服务不可用");  
    }  

private:  
    std::unique_ptr<RemoteService> service_;  
    std::unordered_map<int, std::string> cache_;  
};  

场景2:日志代理(操作审计)

class OrderService {  
public:  
    virtual void placeOrder(const std::string& item) = 0;  
};  

class RealOrderService : public OrderService {  
public:  
    void placeOrder(const std::string& item) override {  
        std::cout << "下单商品: " << item << "\n";  
    }  
};  

class LoggingProxy : public OrderService {  
public:  
    LoggingProxy(std::unique_ptr<OrderService> service)  
        : service_(std::move(service)) {}  

    void placeOrder(const std::string& item) override {  
        log("用户尝试下单: " + item);  
        service_->placeOrder(item);  
        log("下单成功: " + item);  
    }  

private:  
    void log(const std::string& message) {  
        std::cout << "[日志] " << message << "\n";  
    }  
    std::unique_ptr<OrderService> service_;  
};  

5. 优缺点分析

优点​​缺点
解耦客户端与真实对象增加系统复杂度(需维护代理类)
支持访问控制与附加逻辑(日志/缓存)可能引入轻微性能开销(代理层调用)
优化资源利用(如懒加载)过度使用会导致代码冗余

6. 调试与优化策略

调试技巧(VS2022)​

1. ​代理调用跟踪:
  • 在代理类的fetchData()或executeQuery()设置断点,验证逻辑是否正确触发。
2. 验证权限与缓存:
  • 使用 ​监视窗口 检查代理类中的cache_或用户角色状态。

性能优化

1. ​线程安全缓存:
#include <mutex>  
class ThreadSafeProxy : public RemoteService {  
public:  
    std::string fetchData(int id) override {  
        std::lock_guard<std::mutex> lock(cacheMutex_);  
        // ... 原有缓存逻辑  
    }  
private:  
    std::mutex cacheMutex_;  
};  
2. ​延迟初始化优化:
class LazyInitProxy : public Image {  
public:  
    void display() override {  
        if (!realImage_) {  
            realImage_ = std::make_unique<HighResImage>(path_);  
        }  
        realImage_->display();  
    }  
};  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JuicyActiveGilbert

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值