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

介绍

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

实现

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;
}
相关推荐
2601_949817927 分钟前
大厂Java进阶面试解析笔记文档
java·笔记·面试
John.Lewis27 分钟前
C++进阶(12)附加学习:STL之空间配置器(了解)
开发语言·c++·笔记
独小乐29 分钟前
019.ADC转换和子中断|千篇笔记实现嵌入式全栈/裸机篇
linux·c语言·驱动开发·笔记·嵌入式硬件·mcu·arm
xuanwenchao29 分钟前
ROS2学习笔记 - 2、类的继承及使用
服务器·笔记·学习
014-code1 小时前
日志规范:怎么写才不算写废话
java·开发语言·设计模式·日志
楼田莉子2 小时前
同步/异步日志系统:日志落地模块\日志器模块\异步日志模块
linux·服务器·c++·学习·设计模式
сокол3 小时前
【网安-等保评测-基础记录】网络安全等级保护2.0 详解(定级、备案、测评、整改一站式指南)
网络·笔记·网络安全·云计算
qeen876 小时前
【算法笔记】模拟与高精度加减乘除
c++·笔记·算法·高精度·模拟
U盘失踪了6 小时前
什么是B/S 架构和 C/S 架构
笔记
像一只黄油飞7 小时前
第二章-02-注释
笔记·python·学习·零基础