The proxy mode (Proxy) of the design mode, taking C++ as an example, realizes remote proxy, virtual proxy, protection proxy, etc.

        Hello brothers and sisters, it has not been updated for a long time, today I will briefly introduce the proxy mode, a very simple design mode, which aims to control access to the original object through the proxy object without changing the original object. The proxy mode can also be divided into remote proxy, virtual proxy, protection proxy, etc. according to the specific situation, which will be introduced below.

Table of contents

 1. Basic introduction of agent mode

1.1 Basics

1.2 Code example

2. Remote proxy

3. Virtual Proxy

4. Protective Proxy

5. Cache Proxy

6. Summary


 1. Basic introduction of agent mode

1.1 Basics

        The C++ proxy pattern is a structural design pattern whose main purpose is to provide a proxy for other objects to control access to these objects. A proxy object can act as a wrapper around the original object, forwarding requests to the original object, and can perform some additional operations before or after forwarding the request.

        Proxy mode is usually used in the following situations:

  1. Remote Proxy : Used to communicate between two objects in different address spaces, sending requests to remote objects.
  2. Virtual Proxy : Used for lazy loading, i.e. loading resources when needed.

  3. Protection Proxy : Used to control access to objects, for example, only specific users can access an object.

  4. Caching proxy : used to cache the access results of objects to avoid repeated execution of computationally intensive operations.

        Implementing the proxy pattern in C++ can use abstract classes and interfaces to define the communication protocol between the proxy and the original object, and use concrete classes to implement them. The proxy object forwards the request to the original object and can perform some additional operations before or after forwarding the request.

1.2 Code example

        The following is a sample code of a simple C++ proxy mode:

#include <iostream>
using namespace std;

// 定义抽象类 Subject,代表原始对象和代理对象共同的接口
class Subject {
public:
    virtual void request() = 0;
};

// 定义具体类 RealSubject,实现原始对象的功能
class RealSubject : public Subject {
public:
    void request() override {
        cout << "RealSubject: Handling request." << endl;
    }
};

// 定义代理类 Proxy,实现代理对象的功能
class Proxy : public Subject {
private:
    RealSubject* real_subject_;

    void check_access() const {
        cout << "Proxy: Checking access prior to handling request." << endl;
    }

public:
    Proxy(RealSubject* real_subject) : real_subject_(real_subject) {}

    void request() override {
        check_access();
        real_subject_->request();
    }
};

int main() {
    RealSubject* real_subject = new RealSubject;
    Proxy* proxy = new Proxy(real_subject);
    proxy->request();

    delete proxy;
    delete real_subject;
    return 0;
}

        In this example, the abstract class Subject defines the common interface request() of the original object and the proxy object, the concrete class RealSubject realizes the function of the original object, and the proxy class Proxy realizes the function of the proxy object, and executes a Additional operation check_access(). In the main() function, a RealSubject object and a Proxy object are created, and the request() method is called through the Proxy object.

        The class diagram is as follows:

 2. Remote proxy

        A C++ remote proxy is a design pattern that allows clients to access remote services or objects indirectly through a proxy object. This pattern is often used in network programming, such as RPC (Remote Procedure Call) or distributed systems .

// 假设这是远程服务端对象的头文件
class RemoteService {
public:
    virtual void foo() = 0;
};

// 代理类,用于访问远程服务端对象
class RemoteServiceProxy : public RemoteService {
public:
    RemoteServiceProxy(const std::string& host, int port) : m_host(host), m_port(port) {}

    void foo() override {
        // 连接远程服务端
        connect();

        // 向远程服务端发送请求
        sendRequest("foo");

        // 等待远程服务端响应
        std::string response = receiveResponse();

        // 关闭连接
        disconnect();

        // 处理响应
        processResponse(response);
    }

private:
    std::string m_host;
    int m_port;
    int m_socketFd;  // 保存套接字描述符,用于连接远程服务端

    void connect() {
        // 连接远程服务端代码
    }

    void sendRequest(const std::string& request) {
        // 向远程服务端发送请求代码
    }

    std::string receiveResponse() {
        // 从远程服务端接收响应代码
    }

    void disconnect() {
        // 关闭连接代码
    }

    void processResponse(const std::string& response) {
        // 处理响应代码
    }
};

// 客户端代码
int main() {
    RemoteServiceProxy proxy("127.0.0.1", 8080);
    proxy.foo();  // 通过代理对象间接访问远程服务端对象的foo()方法
    return 0;
}

        In the above code, RemoteService is an abstract base class that defines the interface of the remote server object. RemoteServiceProxy is a proxy class that connects to a remote server through a socket descriptor and forwards the client's request to the remote server. The client only needs to access the method of the remote server through the proxy object, without knowing the specific implementation details of the remote server.

        The class diagram is as follows:

3. Virtual Proxy

        The C++ Virtual Proxy (Virtual Proxy) pattern is a structural design pattern that allows you to create a proxy object instead of a real object. The proxy object can control access to the real object and only create or load the real object when needed.

        Code example:

#include <iostream>
using namespace std;

// 定义一个抽象类Subject
class Subject {
public:
    virtual void request() = 0;
};

// 定义一个真实的Subject类RealSubject
class RealSubject : public Subject {
public:
    void request() {
        cout << "真实的请求" << endl;
    }
};

// 定义一个代理类Proxy
class Proxy : public Subject {
private:
    RealSubject *realSubject;

public:
    void request() {
        if (realSubject == nullptr) {
            realSubject = new RealSubject();
        }
        cout << "代理请求" << endl;
        realSubject->request();
    }
};

// 客户端代码
int main() {
    Proxy proxy;
    proxy.request();
    return 0;
}

        In the above example, we defined an abstract class Subject and a concrete class RealSubject, which both implement the request() method. Then we define a proxy class Proxy, which also implements the request() method, but it first checks whether the real subject has been created, and if not, creates one. The proxy class then prints a message indicating the proxy request. Finally, it calls the request() method of the real subject.

        In the client code, we instantiate a proxy object and call the request() method. Since we used the proxy pattern, when we call the request() method of the proxy object, it will first create the real object (if not created), then print the proxy request, and finally call the request() method of the real object.

        One benefit of this pattern is that it delays the creation of the real object until it is actually needed. This can save resources, especially when creating real objects is expensive.

        Class Diagram:

4. Protective Proxy

        Protective Proxy in C++ is a structural design pattern whose purpose is to control access to objects. It uses a proxy object to control access to the original object, and the proxy object provides additional security and protection by restricting or controlling access to the original object.

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

class Image {
public:
    Image(std::string name) : name_(name) {}
    virtual void Display() = 0;
    virtual ~Image() {}

protected:
    std::string name_;
};

class RealImage : public Image {
public:
    RealImage(std::string name) : Image(name) {
        LoadFromDisk();
    }

    void Display() override {
        std::cout << "Displaying " << name_ << std::endl;
    }

private:
    void LoadFromDisk() {
        std::cout << "Loading " << name_ << " from disk" << std::endl;
    }
};

class ImageProxy : public Image {
public:
    ImageProxy(std::string name) : Image(name) {}

    void Display() override {
        if (real_image_ == nullptr) {
            real_image_ = std::make_unique<RealImage>(name_);
        }
        real_image_->Display();
    }

private:
    std::unique_ptr<RealImage> real_image_;
};

int main() {
    // Create a real image object
    auto real_image = std::make_unique<RealImage>("image1.jpg");
    
    // Display the real image
    real_image->Display();

    // Create an image proxy object
    auto image_proxy = std::make_unique<ImageProxy>("image2.jpg");

    // Display the image proxy
    image_proxy->Display();

    // The real image is only loaded once, even though it is displayed twice
    return 0;
}

        In the sample code above, Image is an abstract base class, and RealImage and ImageProxy are concrete classes. RealImage is a real image object that can load and display images from disk. ImageProxy is a proxy object that can access real image objects and is responsible for loading and displaying real image objects. When we call the Display() method of the ImageProxy object, it first checks whether a real image object has been loaded. If not loaded, it will use the RealImage object to load the image. This way can reduce frequent visits to real image objects, thereby improving the efficiency of the program.

        Class Diagram:

5. Cache Proxy

        The basic idea of ​​the caching proxy mode is: in order to avoid repeated calculations every time a function or method is called, we can cache the results, and return the cached results directly when we need them next time without further calculations .

#include <iostream>
#include <unordered_map>

using namespace std;

// 定义一个全局的缓存代理类
class FactorialCacheProxy {
public:
    int getFactorial(int n) {
        if (cache_.find(n) != cache_.end()) {
            // 如果结果已经被缓存,直接返回缓存的结果
            cout << "Get result from cache: " << n << endl;
            return cache_[n];
        } else {
            // 如果结果没有被缓存,进行计算并缓存结果
            cout << "Calculate result: " << n << endl;
            int result = calculateFactorial(n);
            cache_[n] = result;
            return result;
        }
    }
private:
    // 计算阶乘的实际函数
    int calculateFactorial(int n) {
        int result = 1;
        for (int i = 1; i <= n; i++) {
            result *= i;
        }
        return result;
    }
    // 使用一个 unordered_map 来作为缓存
    unordered_map<int, int> cache_;
};

int main() {
    FactorialCacheProxy cacheProxy;
    for (int i = 5; i <= 7; i++) {
        int result = cacheProxy.getFactorial(i);
        cout << "Factorial of " << i << " is " << result << endl;
    }
    for (int i = 5; i <= 7; i++) {
        int result = cacheProxy.getFactorial(i);
        cout << "Factorial of " << i << " is " << result << endl;
    }
    return 0;
}

        Calculate the result and cache the result. When the same method is called again later, the result is directly fetched from the cache without further calculation, thus improving the performance of the program.

6. Summary

        The proxied object of the proxy mode must have some peculiarities. Either the object is difficult to load or the calculation is difficult. It is necessary to design a proxy as a buffer, and the proxy wakes up the real object when necessary. Everything that meets the above characteristics can use the proxy mode, and the design mode is natural, and it is born to solve the pain points in the running of the program.

        The blogger wishes everyone a happy weekend!

Guess you like

Origin blog.csdn.net/weixin_44120785/article/details/130019252