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


    一、什么是代理模式(Proxy Pattern)

    代理模式(Proxy Pattern)是一种结构型设计模式,它允许一个对象(代理)充当另一个对象(真实对象)的接口,以控制对该对象的访问。代理对象可以在访问真实对象之前或之后执行一些操作,从而增强或限制真实对象的行为。

    代理模式的主要目的是为了控制访问,而不是简单地添加功能。它可以用于实现以下目标:

    1. 代理模式的主要目的是为了控制访问,而不是简单地添加功能。它可以用于实现以下目标:
    2. 虚拟代理: 代理对象在需要时才实例化真实对象。这可以用于减少启动时间,或者对于昂贵的对象,可以延迟其创建。
    3. 保护代理: 代理对象控制对真实对象的访问,可以添加权限控制或访问限制。
    4. 缓存代理: 代理对象可以缓存真实对象的信息,以便在后续访问中提高性能。
    5. 日志记录代理: 代理对象可以记录对真实对象的操作,以进行日志记录、性能监测等。

    在代理模式中,通常有以下角色:

    1. 抽象主题(Subject): 定义了真实对象和代理对象的共同接口,以确保代理对象可以替代真实对象。
    2. 真实主题(Real Subject): 实际的业务对象,是代理所代表的对象,具有真正的功能。
    3. 代理(Proxy): 提供与真实对象相同的接口,可以对真实对象的访问进行控制和管理。

    代理模式的优势包括:

    • 控制对真实对象的访问,从而可以进行权限控制、延迟加载等操作。
    • 提供额外的功能,如日志记录、缓存等,而不需要修改真实对象。

    然而,代理模式也可能引入了复杂性,因为需要创建额外的代理类。在使用代理模式时,需要根据情况权衡代理的好处和代理类的数量。

    二、代理模式的一个现实应用场景

    一个现实的应用场景,可以通过一个虚拟代理的例子来解释代理模式。

    场景:虚拟图片加载器

    假设你正在开发一个图片浏览器应用,其中用户可以浏览并查看大量的高分辨率图片。然而,由于这些图片可能非常大,加载它们可能需要一些时间,特别是在网络较慢的情况下。为了提高用户体验并减少加载时间,你可以使用代理模式来实现一个虚拟图片加载器。

    在这个场景中,有以下几个角色:

    1. 抽象主题(Image): 定义了图片的共同接口,可以是真实图片和代理图片的共同基类。
    2. 真实主题(RealImage): 实际的高分辨率图片对象,具有加载和显示的功能。
    3. 代理(ProxyImage): 代理图片对象,具有与真实图片相同的接口,但它并不立即加载真实图片,而是在需要时才加载。此外,代理还可以在加载前显示一些低分辨率的缩略图。

    在这个场景中,代理模式的好处显而易见:

    • 用户在查看图片时,不需要等待图片加载完成,而是先显示缩略图,从而提高了用户体验。
    • 只有在用户真正需要查看大图时,才会进行真正的图片加载,从而减少了不必要的加载时间和网络资源消耗。

    总之,代理模式在这个应用场景中通过虚拟图片加载器的实现,提供了一种有效的方式来控制和优化图片的加载和显示,从而提高了用户体验。

    三、代理模式的代码样例

    下面是一个使用 C++ 实现代理模式的简单示例,以虚拟图片加载器为例:

    #include 
    
    // 抽象主题
    class Image {
    public:
        virtual void display() = 0;
        virtual ~Image() {}
    };
    
    // 真实主题
    class RealImage : public Image {
    private:
        std::string filename;
    
    public:
        RealImage(const std::string& filename) : filename(filename) {
            loadImageFromDisk();
        }
    
        void loadImageFromDisk() {
            std::cout << "Loading image from disk: " << filename << std::endl;
        }
    
        void display() override {
            std::cout << "Displaying image: " << filename << std::endl;
        }
    };
    
    // 代理
    class ProxyImage : public Image {
    private:
        RealImage* realImage;
        std::string filename;
    
    public:
        ProxyImage(const std::string& filename) : filename(filename), realImage(nullptr) {}
    
        void display() override {
            if (!realImage) {
                realImage = new RealImage(filename);
            }
            realImage->display();
        }
    
        ~ProxyImage() {
            if (realImage) {
                delete realImage;
            }
        }
    };
    
    int main() {
        Image* image1 = new ProxyImage("image1.jpg");
        Image* image2 = new ProxyImage("image2.jpg");
    
        image1->display();  // 实际图片会被加载和显示
        image2->display();  // 实际图片会被加载和显示
    
        delete image1;
        delete image2;
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    在这个示例中,我们定义了一个抽象主题 Image,一个真实主题 RealImage 用于加载和显示实际图片,以及一个代理 ProxyImage 用于延迟加载真实图片,并在需要时显示。在 main 函数中,我们通过代理对象加载和显示图片。

    这个示例演示了代理模式的概念,代理对象可以控制和管理对真实对象的访问。

    四、使用代理模式需要注意的问题

    在使用代理模式时,需要注意以下几个问题:

    1. 性能问题: 虽然代理模式可以在某些情况下提高性能(例如延迟加载),但代理本身可能会引入一定的开销,特别是在代理对象需要频繁创建和销毁时。需要权衡代理的好处和性能影响。
    2. 代理的数量: 过多的代理对象可能会导致类的数量增加,增加代码的复杂性。在选择使用代理模式时,需要考虑代理的数量是否合理,以避免引入过多的类。
    3. 代理的一致性: 代理对象需要和真实对象具有一致的接口,以便可以无缝替换。确保代理对象的接口与真实对象保持一致,从而避免类型不匹配的问题。
    4. 资源管理: 如果代理对象涉及到资源的管理,如内存释放、文件关闭等,需要确保代理对象在不再使用时能够正确地进行资源清理,以避免资源泄漏。
    5. 并发安全: 如果多个线程同时访问代理对象,需要考虑并发安全性。适当的同步机制可能需要用于保护代理对象的状态。
    6. 生命周期管理: 代理对象的生命周期需要得到管理,包括创建、销毁和内存管理。确保代理对象在不再需要时能够正确地释放资源。
    7. 应用场景: 代理模式并不适用于所有情况。在一些简单的场景中,直接使用真实对象可能更简单和直观。只有在需要控制访问、添加额外功能、延迟加载等情况下,才考虑使用代理模式。
    8. 不应过度使用: 代理模式是为了控制访问,而不是为了简单地添加功能。过度使用代理模式可能会引入不必要的复杂性,降低代码的可读性和维护性。

    总之,代理模式在合适的场景下可以提供许多好处,但也需要权衡好处和代理所引入的复杂性、性能和维护成本。在使用代理模式时,需根据具体情况谨慎决策,并确保代理对象能够正确地管理资源和状态。

    在这里插入图片描述

  • 相关阅读:
    《机器学习实战》9.树回归
    CF1490F Equalize the Array
    Coinbase早期投资人Garry:我对比特币有充足的预见 2021-04-16
    windows系统安装python教程,以及PyCharm安装,新手入门详细
    初识c++
    react跨域如何解决?
    分布式ID系统设计(1)
    【直播预约中】 腾讯大数据 x StarRocks|构建新一代实时湖仓
    【饭谈-鸡血篇】自以为对,就是错。
    Redis趋势—NVM内存
  • 原文地址:https://blog.csdn.net/qq_38177302/article/details/132588231