• C++设计模式——Proxy代理模式


    一,代理模式简介

    代理模式是一种 结构型设计模式,该模式通过引入一个新的代理对象Proxy,来间接访问原始对象,从而使访问方式变得灵活和可控。
    代理对象的设定减少了客户端与真实对象之间的直接交互。
    通过引入代理对象来间接访问原始的对象,达到延迟访问和隔离的效果,这就是代理模式的主要用途。
    举个例子:
    当有多个客户端对数据库发起大批量请求时,数据库由于需要同时处理多个请求,导致其处理速度变得很慢。
    此时如果有一个代理,用法上和数据库一致,这个代理先收集来自多个客户端的请求,进行缓存,然后逐渐转发给数据库,避免了通道发生阻塞,那么数据库此时的处理速度会大大提升。

    二,代理模式的结构

    1.抽象对象(Subject):定义了真实对象和代理对象的共同接口。

    2.真实对象(RealSubject):又称为被代理对象,代理模式中的核心角色,定义了真正需要被代理的业务逻辑

    3.代理对象(Proxy):充当了客户端与真实对象之间的中介。

    对应UML类图:

    1.Subject定义了Proxy和RealSubject的公共接口。

    2.Proxy和RealSubject都实现了Subject的接口。

    3.客户端(Client)通过Proxy与RealSubject进行交互。

    4.RealSubject负责完成主要的接口实现,Proxy负责控制外部Client对接口的访问。

    5.Proxy内部包含对Subject的对象指针或引用,因此Proxy可以进一步调用子类RealSubject中的函数(forward calls)。

    6.在某些情况下,Proxy可以用来完成RealSubject实例的创建与销毁。

    7.Client是使用Proxy的对象,它通过Proxy来访问和操作RealSubject。

    代码实现:

    1. #include
    2. using namespace std;
    3. class Subject
    4. {
    5. public:
    6. virtual void request() = 0;
    7. virtual ~Subject() {}
    8. };
    9. class RealSubject : public Subject
    10. {
    11. public:
    12. void request() {
    13. cout << "RealSubject.request()" << endl;
    14. }
    15. };
    16. class Proxy : public Subject
    17. {
    18. private:
    19. Subject* realSubject;
    20. public:
    21. Proxy()
    22. {
    23. realSubject = new RealSubject();
    24. }
    25. ~Proxy()
    26. {
    27. delete realSubject;
    28. }
    29. // Forward calls to the RealSubject:
    30. void request() {
    31. realSubject->request();
    32. }
    33. };
    34. int main() {
    35. Proxy p;
    36. p.request();
    37. }

    运行结果:

    RealSubject.request()

    补充:在C++编码中,确实可以通过继承和虚函数实现父类调用子类的成员函数,这是C++多态特性的一种常见应用方式。

    1. #include
    2. using namespace std;
    3. class Base {
    4. public:
    5. virtual void print() {
    6. cout << "Base class method" << endl;
    7. }
    8. };
    9. class Derived : public Base {
    10. public:
    11. // 重写父类的虚函数
    12. virtual void print() override {
    13. cout << "Derived class method" << endl;
    14. }
    15. };
    16. int main() {
    17. // 父类对象调用子类方法
    18. Base* baseObj = new Derived();
    19. baseObj->print();
    20. }

    运行结果:

    Derived class method

    三,代理模式的种类

    简单代理(Simple Proxy):主要用于转发请求和处理一些基本操作,例如添加日志、计时等。

    远程代理(Remote Proxy):当主体对象在另一个地址空间(如网络地址)时,远程代理会提供远程通信的功能,进行数据的访问和转换。

    智能引用代理(Smart Reference Proxy):也称为共享代理,它维护了多个客户端对同一目标的共享引用,并提供统一的接口。

    虚拟代理(Virtual Proxy):延迟针对昂贵资源的访问,只有在真正使用时才加载。

    保护代理(Protection Proxy):主要用于访问权限的控制,比如身份验证、授权等。

    四,代理模式的应用场景

    1.延迟加载:使资源密集型的对象仅仅在被使用时才加载,例如,访问大型数据库、加载大批量图像数据等。

    2.访问控制:代理可以通过添加身份验证来控制对真实主体的访问,可用于保护敏感数据。

    3.缓存机制:代理可以缓存高频次的请求,从而减少系统开销,优化性能。

    4.日志记录和监控:代理可用于记录或监控对真实主体执行的操作,而无需修改其代码。

    5.远程访问:在分布式系统中,真实主体可能位于不同的计算机上,代理模式可以隐藏远程通信的复杂细节。

    6.状态管理:代理可以同步管理多个客户端所共享的真实主体的状态,确保它们的一致性。

    五,代理模式的优缺点

    代理模式的优点:

    可以在不修改被代理对象的情况下,增加额外的功能或控制访问方式。

    可以在访问对象之前和之后进行一些处理,比如添加日志、添加时间戳等。

    可以实现远程代理,使得客户端可以通过网络访问远程的对象。

    可以防止未经授权访问真实主体。

    代理模式的缺点:

    引入新的类,增加代码复杂性。

    读取资源时,需要通过代理来间接访问,造成额外的性能损失。

    六,代码实战

    开发场景:基于Proxy模式来模拟对图片的延迟加载和显示控制。

    1.创建Subject

    1. //Step 1: Define the Subject interface
    2. class Image {
    3. public:
    4. virtual void display() = 0;
    5. };

    2.创建RealSubject

    1. //Step 2: Implement the Real Object
    2. class RealImage : public Image {
    3. private:
    4. std::string filename;
    5. public:
    6. RealImage(const std::string& filename) : filename(filename) {
    7. // Simulate loading the image
    8. std::cout << "Loading image: " << filename << std::endl;
    9. }
    10. void display() override {
    11. std::cout << "Displaying image: " << filename << std::endl;
    12. }
    13. };

    3.Proxy类实现与RealSubject相同的接口,并维护对RealSubject的引用。

    1. //Step 3: Create the Proxy
    2. class ImageProxy : public Image {
    3. private:
    4. // Reference to the Real Object
    5. RealImage* realImage;
    6. std::string filename;
    7. public:
    8. ImageProxy(const std::string& filename) : filename(filename), realImage(nullptr) {}
    9. void display() override {
    10. if (realImage == nullptr) {
    11. realImage = new RealImage(filename);
    12. }
    13. realImage->display();
    14. }
    15. };

    完整代码实现:

    1. #include
    2. #include
    3. using namespace std;
    4. class Image {
    5. public:
    6. virtual void display() = 0;
    7. };
    8. class RealImage : public Image {
    9. private:
    10. std::string filename;
    11. public:
    12. RealImage(const std::string& filename) : filename(filename) {
    13. // Simulate loading the image
    14. std::cout << "Loading image: " << filename << std::endl;
    15. }
    16. void display() override {
    17. std::cout << "Displaying image: " << filename << std::endl;
    18. }
    19. };
    20. class ImageProxy : public Image {
    21. private:
    22. // Reference to the Real Object
    23. RealImage* realImage;
    24. std::string filename;
    25. public:
    26. ImageProxy(const std::string& filename) : filename(filename), realImage(nullptr) {}
    27. void display() override {
    28. if (realImage == nullptr) {
    29. realImage = new RealImage(filename);
    30. }
    31. realImage->display();
    32. }
    33. };
    34. int main() {
    35. //Create a proxy to an image
    36. Image* image = new ImageProxy("example.jpg");
    37. //Display the image
    38. image->display();
    39. //Displaying the image again
    40. image->display();
    41. delete image;
    42. return 0;
    43. }

    运行结果:

    1. Loading image: example.jpg
    2. Displaying image: example.jpg
    3. Displaying image: example.jpg

    七,参考阅读

    https://www.geeksforgeeks.org/proxy-pattern-c-design-patterns/

    https://www.bogotobogo.com/DesignPatterns/proxy.php

    https://design-patterns.readthedocs.io/zh-cn/latest/structural_patterns/proxy.html

    https://refactoring.guru/design-patterns/proxy

  • 相关阅读:
    深度解析单例模式
    Spring 的依赖注入(DI)
    2023版 STM32实战7 通用同步/异步收发器(串口)F103/F407
    2013-2020年全国31省数字经济信息化基础数据
    【C# 调试】.net中的 .pdb文件是什么,有什么用
    【量化交易笔记】12.海龟交易策略
    类的生命周期
    Spring&SpringMVC&SpringBoor
    15——go语言中的流程控制
    tomcat安装与基本使用
  • 原文地址:https://blog.csdn.net/CoderZZ_2024/article/details/139667720