《设计模式的艺术》笔记 - 代理模式

介绍

代理模式是给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式是一种对象结构型模式。

实现

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <unordered_map>

class Subject {     // 抽象主题角色
public:
    virtual void request() = 0;
};

class Proxy : public Subject {  // 代理主题角色
public:
    Proxy();
    ~Proxy();

    void request() override;

    void preRequest();

    void postRequest();
private:
    Subject *m_real;
};

class RealSubject : public Subject {
public:
    void request() override;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"

Proxy::Proxy() {
    m_real = new RealSubject();
}

Proxy::~Proxy() {
    if (m_real) {
        delete m_real;
    }
}

void Proxy::request() {
    if (m_real) {
        preRequest();
        m_real->request();
        postRequest();
    }
}

void Proxy::preRequest() {
    std::cout << "代理请求准备工作" << std::endl;
}

void Proxy::postRequest() {
    std::cout << "代理结束收尾工作" << std::endl;
}

void RealSubject::request() {
    std::cout << "被代理的请求" << std::endl;
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    Subject *proxy = new Proxy();
    proxy->request();
    delete proxy;

    return 0;
}

总结

优点

  1. 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度,满足迪米特法则。

  2. 客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则,系统具有较好的灵活性和可扩展性。

  3. 远程代理为位于两个不同地址空间对象的访问提供了一种实现机制,可以将一些消耗资源较多的对象和操作移至性能更好的计算机上,提高系统的整体运行效率。

  4. 虚拟代理通过一个消耗资源较少的对象来代表一个消耗资源较多的对象,可以在一定程度上节省系统的运行开销。

  5. 保护代理可以控制对一个对象的访问权限,为不同用户提供不同级别的使用权限。

缺点

  1. 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢,例如保护代理。

  2. 实现代理模式需要额外的工作,有些代理模式的实现非常复杂,例如远程代理。

适用场景

  1. 当客户端对象需要访问远程主机中的对象时,可以使用远程代理。

  2. 当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时,可以使用虚拟代理。例如一个对象需要很长时间才能完成加载时。

  3. 当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时,可以使用保护代理。

  4. 当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时,可以使用缓冲代理。通过缓冲代理,系统无须在客户端每次访问时都重新执行操作,只需直接从临时缓冲区获取操作结果即可。

  5. 当需要为一个对象的访问(引用)提供一些额外的操作时,可以使用智能引用代理。

练习

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <unordered_map>
#include <atomic>

class Subject {     // 抽象主题角色
public:
    virtual void displayUrl(const std::string &url) = 0;
    virtual void displayPic(const std::string &pic) = 0;
};

class Proxy : public Subject {  // 代理主题角色
public:
    Proxy();
    ~Proxy();

    void displayUrl(const std::string &url) override;
    void displayPic(const std::string &pic) override;

private:
    Subject *m_real;
};

class RealSubject : public Subject {
public:
    void displayUrl(const std::string &url) override;
    void displayPic(const std::string &pic) override;

    void download(const std::string &url);

    bool isDownloadComplete();

private:
    bool m_isDownloaded;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"
#include <thread>
#include <unistd.h>

Proxy::Proxy() {
    m_real = new RealSubject();
}

Proxy::~Proxy() {
    if (m_real) {
        delete m_real;
    }
}

void Proxy::displayUrl(const std::string &url) {
    if (m_real) {
        new std::thread(&Subject::displayUrl, m_real, std::ref(url));
    }
    std::cout << "显示图片" << url << std::endl;
}

void Proxy::displayPic(const std::string &pic) {
    if (m_real) {
        m_real->displayPic(pic);
    }
}

void RealSubject::download(const std::string &url) {
    sleep(10);
    std::cout << url << "下载完成" << std::endl;
    m_isDownloaded = true;
}

bool RealSubject::isDownloadComplete() {
    return m_isDownloaded;
}

void RealSubject::displayUrl(const std::string &url) {
    download(url);
}

void RealSubject::displayPic(const std::string &pic) {
    while (!m_isDownloaded) {
        usleep(100000);
    }
    std::cout << "显示图片" << pic << std::endl;
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    Subject *proxy = new Proxy();
    proxy->displayUrl("http://www.123.com/ab.jpg");
    proxy->displayPic("ab.jpg");
    delete proxy;

    return 0;
}
相关推荐
吗喽154345188几秒前
渗透高级第一次作业(笔记整理)
笔记·安全·网络安全
小+不通文墨11 分钟前
“示波器的调节和使用”实验报告
经验分享·笔记·学习·学习方法
2501_9377983932 分钟前
2026年GEO行业趋势与企业服务选型指南
笔记
Jerry_Gao92135 分钟前
【成长笔记】【web安全】深入Web安全与PHP底层:四天实战课程笔记
笔记·安全·web安全·php·漏洞
wdfk_prog1 小时前
[Linux]学习笔记系列 -- [drivers][base]cpu
linux·笔记·学习
九皇叔叔1 小时前
使用 perf + FlameGraph 生成火焰图(Flame Graph)笔记
笔记·性能分析·火焰图
℡終嚸♂6802 小时前
渗透测试前四天笔记
笔记
小屁猪qAq2 小时前
设计模式总纲
开发语言·c++·设计模式
妄汐霜3 小时前
小白学习笔记(MySQL基础中其他知识)
笔记·学习·mysql
小简GoGo3 小时前
前端常用设计模式快速入门
javascript·设计模式