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

发布时间:2024年01月18日

介绍

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

实现

myclass.h

//
// 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

//
// 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

#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

//
// 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

//
// 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

#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;
}

文章来源:https://blog.csdn.net/yuweiping5247/article/details/135680100
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。