设计模式 - 代理模式(Proxy Pattern)

设计模式 - 代理模式(Proxy Pattern)

代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供了一种代理,以控制对这个对象的访问。代理模式可以用于延迟对象的创建和初始化、控制对对象的访问、在访问对象时添加额外的功能等。

flyfish

代理模式的关键概念

  • 代理(Proxy) :实现与目标对象相同的接口,用来控制对目标对象的访问。

  • 目标对象(RealSubject) :定义了代理对象代表的真实对象。

  • 客户端(Client) :通过代理对象间接访问目标对象。

应用场景

延迟初始化(虚拟代理)

如果你有一个需要很多资源但并不经常使用的对象,可以使用代理模式。这种情况下,代理可以在你第一次需要对象时才真正创建它,而不是在程序启动时就创建。这种方式可以节省系统资源,直到你确实需要使用这个对象。

访问控制(保护代理)

当你想限制只有某些客户端可以访问某个对象时,可以使用代理模式。例如,如果这个对象是操作系统的重要部分,而你只希望合法的程序访问它,代理可以在检查客户端的权限后再决定是否允许访问。

远程服务的本地执行(远程代理)

当你的服务对象在远程服务器上时,可以使用代理模式。在这种情况下,代理会处理所有与网络相关的细节,比如通过网络发送请求。这样客户端就可以像使用本地对象一样使用远程对象,而不用关心网络通信的复杂性。

记录日志(日志记录代理)

如果你需要记录对某个服务对象的请求历史,可以使用代理模式。代理可以在将请求传递给服务对象之前,先把请求信息记录下来。这对调试或审计很有帮助。

缓存请求结果(缓存代理)

当请求的结果非常大或者生成这些结果需要花费很多时间时,可以使用代理模式来缓存这些结果。代理可以保存已经请求过的结果,以便在再次请求相同结果时直接返回缓存,而不是重新计算。

智能引用

当一个耗费大量资源的对象不再被使用时,你可能想要立即销毁它以释放系统资源。代理可以记录哪些客户端正在使用这个对象,并在没有客户端使用时销毁它。此外,如果对象没有被修改,代理还可以让其他客户端复用它,从而避免不必要的重复创建。

这些代理模式的应用场景让你的系统更高效、更安全,同时也使得某些功能的实现变得更加简洁。

一个简单的例子

  1. Subject 类 :定义了抽象接口,RealSubjectProxy 都实现了这个接口。

  2. RealSubject 类 :目标对象,包含实际的请求处理逻辑。

  3. Proxy 类 :代理对象,控制对目标对象的访问,可以在访问前后添加额外的功能,如权限检查和日志记录。

  4. ClientCode 函数 :客户端代码,通过代理访问目标对象。

  5. main 函数 :展示了如何使用代理模式通过代理访问目标对象。

#include <iostream>
#include <memory>

// 抽象接口类,定义真实对象和代理对象的公共接口
class Subject {
public:
    virtual void Request() const = 0; // 抽象方法,具体操作由子类实现
    virtual ~Subject() = default; // 虚析构函数,确保正确析构子类
};

// 目标对象类,定义了代理所代表的真实对象
class RealSubject : public Subject {
public:
    void Request() const override {
        std::cout << "RealSubject: Handling request." << std::endl; // 处理请求
    }
};

// 代理类,实现与目标对象相同的接口
class Proxy : public Subject {
private:
    std::unique_ptr<RealSubject> real_subject_; // 目标对象指针

    // 检查访问权限的私有方法
    bool CheckAccess() const {
        std::cout << "Proxy: Checking access before firing a real request." << std::endl;
        // 在这里可以进行权限检查,返回 true 表示有权限
        return true;
    }

    // 记录日志的私有方法
    void LogAccess() const {
        std::cout << "Proxy: Logging the time of request." << std::endl;
        // 在这里可以记录访问日志
    }

public:
    // 构造函数,初始化目标对象
    Proxy() : real_subject_(std::make_unique<RealSubject>()) {}

    void Request() const override {
        // 先检查访问权限
        if (CheckAccess()) {
            // 调用真实对象的请求处理方法
            real_subject_->Request();
            // 记录日志
            LogAccess();
        }
    }
};

// 客户端代码,通过代理访问真实对象
void ClientCode(const Subject& subject) {
    subject.Request(); // 通过代理调用请求
}

int main() {
    std::cout << "Client: Executing client code with a real subject:" << std::endl;
    RealSubject real_subject; // 创建真实对象
    ClientCode(real_subject); // 直接使用真实对象

    std::cout << std::endl;

    std::cout << "Client: Executing the same client code with a proxy:" << std::endl;
    Proxy proxy; // 创建代理对象
    ClientCode(proxy); // 使用代理对象

    return 0;
}

模拟了一个第三方视频服务的远程接口,并通过代理类缓存请求结果以节省网络带宽

  1. ThirdPartyTVLib 接口 :定义了视频服务的基本功能,包括列出视频、获取视频信息和下载视频。

  2. ThirdPartyTVClass 类 :实现了 ThirdPartyTVLib 接口,模拟与远程视频服务的连接。

  3. CachedTVClass 类 :实现了 ThirdPartyTVLib 接口,并在代理对象中实现了缓存功能,减少重复请求。

  4. TVManager 类 :使用服务接口来渲染视频列表和视频页面,通过代理对象间接访问服务对象。

  5. Application 类 :初始化服务对象、代理对象和管理器,并模拟用户交互。

#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#include <memory>

// 远程服务接口,定义了视频服务的基本功能
class ThirdPartyTVLib {
public:
    virtual std::vector<std::string> listVideos() = 0;     // 列出视频
    virtual std::string getVideoInfo(int id) = 0;          // 获取视频信息
    virtual void downloadVideo(int id) = 0;                // 下载视频
    virtual ~ThirdPartyTVLib() = default;                  // 虚析构函数
};

// 服务连接器的具体实现,模拟与腾讯视频的连接
class ThirdPartyTVClass : public ThirdPartyTVLib {
public:
    std::vector<std::string> listVideos() override {
        std::cout << "Fetching list of videos from Tencent Video." << std::endl;
        // 模拟 API 请求
        return {"Video1", "Video2", "Video3"};
    }

    std::string getVideoInfo(int id) override {
        std::cout << "Getting video info for video ID " << id << " from Tencent Video." << std::endl;
        // 模拟获取视频元数据
        return "Video Info for ID " + std::to_string(id);
    }

    void downloadVideo(int id) override {
        std::cout << "Downloading video ID " << id << " from Tencent Video." << std::endl;
        // 模拟下载视频
    }
};

// 缓存代理类,缓存视频请求结果以减少网络请求
class CachedTVClass : public ThirdPartyTVLib {
private:
    std::unique_ptr<ThirdPartyTVLib> service_;                       // 实际服务对象
    std::vector<std::string> listCache_;                             // 视频列表缓存
    std::unordered_map<int, std::string> videoCache_;                // 视频信息缓存
    bool needReset_ = true;                                          // 是否需要重置缓存

public:
    // 构造函数,初始化实际服务对象
    explicit CachedTVClass(std::unique_ptr<ThirdPartyTVLib> service) : service_(std::move(service)) {}

    std::vector<std::string> listVideos() override {
        if (listCache_.empty() || needReset_) {
            listCache_ = service_->listVideos();
            needReset_ = false; // 获取后重置标志
        }
        return listCache_;
    }

    std::string getVideoInfo(int id) override {
        if (videoCache_.find(id) == videoCache_.end() || needReset_) {
            videoCache_[id] = service_->getVideoInfo(id);
            needReset_ = false;
        }
        return videoCache_[id];
    }

    void downloadVideo(int id) override {
        if (!downloadExists(id) || needReset_) {
            service_->downloadVideo(id);
            needReset_ = false;
        }
    }

private:
    // 私有辅助方法,检查下载是否存在(模拟功能)
    bool downloadExists(int id) {
        // 假设每次都需要下载(这里可实现实际检查逻辑)
        return false;
    }
};

// GUI 管理类,负责渲染视频信息
class TVManager {
protected:
    ThirdPartyTVLib* service_; // 使用原始指针指向服务接口

public:
    // 构造函数,初始化服务接口
    explicit TVManager(ThirdPartyTVLib* service) : service_(service) {}

    void renderVideoPage(int id) {
        std::string info = service_->getVideoInfo(id);
        std::cout << "Rendering video page for video ID " << id << ": " << info << std::endl;
    }

    void renderListPanel() {
        std::vector<std::string> list = service_->listVideos();
        std::cout << "Rendering video list panel: ";
        for (const auto& video : list) {
            std::cout << video << " ";
        }
        std::cout << std::endl;
    }

    void reactOnUserInput() {
        renderListPanel(); // 模拟用户输入反应
        renderVideoPage(1); // 模拟用户选择视频 ID 为 1
    }
};

// 应用程序类,初始化代理和管理器
class Application {
public:
    void init() {
        std::unique_ptr<ThirdPartyTVLib> aTVService = std::make_unique<ThirdPartyTVClass>();
        std::unique_ptr<ThirdPartyTVLib> aTVProxy = std::make_unique<CachedTVClass>(std::move(aTVService));
        TVManager manager(aTVProxy.get());
        manager.reactOnUserInput();
    }
};

int main() {
    Application app;
    app.init(); // 初始化应用程序
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

西笑生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值