Bootstrap

设计模式——代理模式

一、定义与概念

  • 定义
    C++ 代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。在代理模式中,存在一个真实对象(被代理对象)和一个代理对象,客户端通过代理对象来间接访问真实对象,代理对象可以在访问真实对象前后进行一些额外的操作,比如权限检查、延迟加载、缓存等。
  • 核心思想
    通过引入代理对象来代替真实对象处理客户端的请求,代理对象和真实对象实现相同的接口,这样对于客户端来说,它不需要知道是在与真实对象还是代理对象打交道,而代理对象可以在必要时对请求进行预处理或后处理。

二、结构和组成部分

抽象主题(Subject)接口

  • 定义:
    这是真实对象和代理对象共同实现的接口,它定义了客户端可以调用的方法,确保了客户端对真实对象和代理对象的使用具有一致性。
  • 代码示例(简单的文件读取接口)
class FileReaderSubject {
public:
    virtual std::string readFile(const std::string& fileName) = 0;
    virtual ~FileReaderSubject() {}
};

真实主题(Real Subject)

  • 定义:
    真实主题是被代理的对象,它实现了抽象主题接口,提供了真实的功能实现。
  • 代码示例(实际的文件读取类)
class RealFileReader : public FileReaderSubject {
public:
    std::string readFile(const std::string& fileName) override {
        std::ifstream file(fileName);
        if (file.is_open()) {
            std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
            file.close();
            return content;
        }
        return "File not found or cannot be opened.";
    }
};

代理(Proxy)

  • 定义:
    代理类也实现了抽象主题接口,它内部包含一个指向真实主题的指针。代理类在实现接口方法时,通常会先进行一些额外的操作,然后再调用真实主题的相应方法,最后可能还会进行一些后续操作。
  • 代码示例(文件读取代理类,带缓存功能)
class FileReaderProxy : public FileReaderSubject {
private:
    RealFileReader* realReader;
    std::unordered_map<std::string, std::string> fileCache;

public:
    FileReaderProxy() : realReader(nullptr) {}

    std::string readFile(const std::string& fileName) override {
        if (fileCache.find(fileName)!= fileCache.end()) {
            return fileCache[fileName];
        }
        if (!realReader) {
            realReader = new RealFileReader();
        }
        std::string content = realReader->readFile(fileName);
        fileCache[fileName] = content;
        return content;
    }

    ~FileReaderProxy() {
        delete realReader;
    }
};

三、应用场景

远程代理

  • 解释:
    当客户端需要访问位于远程服务器上的对象时,可以使用远程代理。远程代理在本地代表远程对象,它负责与远程服务器进行通信,将客户端的请求发送到远程服务器,并将远程服务器的响应返回给客户端。这样,客户端就可以像访问本地对象一样访问远程对象,隐藏了远程调用的复杂性。
  • 示例:
    在分布式系统中,一个客户端想要访问远程数据库中的数据。通过创建远程数据库对象的代理,代理负责将客户端的数据查询请求发送到远程数据库服务器,接收服务器返回的数据,并将其传递给客户端。

虚拟代理

  • 解释:
    虚拟代理用于在需要时才创建和初始化被代理的对象,通常用于处理资源密集型对象。当客户端请求访问一个对象时,如果该对象尚未创建或初始化,虚拟代理会先进行一些轻量级的操作,如显示一个占位符,然后在合适的时候再创建和初始化真实对象,并将客户端的请求转发给真实对象。
  • 示例:
    在一个图像浏览系统中,当用户浏览图像列表时,图像可能是高分辨率的资源密集型对象。此时可以使用虚拟代理,在图像未完全加载之前,代理显示一个低分辨率的占位图像,当用户真正点击查看某张图像时,虚拟代理再去加载和显示高分辨率的真实图像。

保护代理

  • 解释:
    保护代理用于控制对真实对象的访问权限。它可以在客户端访问真实对象之前进行权限检查,如果客户端具有访问权限,则允许访问,否则拒绝访问。这样可以保护真实对象不被未授权的客户端访问。
  • 示例:
    在企业内部的文件管理系统中,有一些机密文件只有特定的用户角色(如管理员或具有特定权限的员工)可以访问。通过使用保护代理,在用户请求访问文件时,代理先检查用户的权限,如果权限符合要求,则调用真实的文件读取操作,否则返回访问被拒绝的提示。

四、优缺点

优点

  • 访问控制:
    可以有效地控制对真实对象的访问,通过代理对象进行权限检查等操作,保护真实对象的安全性。
  • 增强功能:
    代理对象可以在不改变真实对象的基础上,为真实对象添加额外的功能,如缓存、延迟加载、性能优化等,提高了系统的灵活性和可扩展性。
  • 解耦:
    代理模式将客户端与真实对象解耦,客户端不需要了解真实对象的具体实现细节,即使真实对象的实现发生变化,只要代理对象和真实对象之间的接口不变,客户端代码就不需要修改。

缺点

  • 增加复杂性:
    引入代理对象增加了系统的复杂性,特别是当存在多个代理类且它们的逻辑较为复杂时,代码的理解和维护成本会增加。
  • 性能开销:
    在某些情况下,代理对象的额外操作(如权限检查、缓存管理等)可能会带来一定的性能开销,尤其是在对性能要求极高的场景中,需要谨慎考虑代理模式的使用。

代理模式在很多场景下能够为系统带来诸多好处,但需要综合考虑其优缺点,根据实际需求合理使用。

;