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

介绍

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

实现

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;
}
相关推荐
2401_858286113 小时前
L7.【LeetCode笔记】相交链表
笔记·leetcode·链表
龙中舞王5 小时前
Unity学习笔记(2):场景绘制
笔记·学习·unity
青椒大仙KI116 小时前
24/11/7 算法笔记 PCA主成分分析
笔记·算法·信息可视化
光明中黑暗6 小时前
机器学习 笔记
人工智能·笔记·机器学习
明辉光焱7 小时前
Node.js笔记
javascript·笔记·node.js
RationalDysaniaer7 小时前
gin入门
笔记·gin
在下方方8 小时前
【快捷入门笔记】mysql基本操作大全-SQL表
笔记·sql·mysql
kjyzx669 小时前
期刊论文查重率多少,才会不被认定为学术不端?
笔记
瞎姬霸爱.10 小时前
设计模式-七个基本原则之一-里氏替换原则
java·设计模式·里氏替换原则
CXDNW10 小时前
【网络面试篇】其他面试题——Cookie、Session、DNS、CDN、SSL/TLS、加密概念
网络·笔记·面试·cdn·dns·cookie