设计模式16-代理模式

news2024/11/28 19:51:15

设计模式16-代理模式

  • 动机
  • 定义与结构
    • 模式定义
    • 结构
  • 代码推导
  • 特点
  • 应用
  • 总结
  • 实例说明
      • 1. 远程代理
      • 2. 虚拟代理
      • 3. 保护代理
      • 4. 智能引用代理

动机

  • 在面向对象系统中有一些对象由于某种原因比如对象创建的开销很大或者某些操作需要安全控制,或者需要进程外的访问等情况。直接访问会给使用者或者系统结构带来许多麻烦。
  • 那么如何在不失去透明操作对象的同时来管理和控制这些对象特有的复杂性?增加一层间接层是软件开发中常见的解决方式。
  • 代理模式的主要动机是为某个对象提供一个代理或占位符,以便控制对该对象的访问。这种模式可以在不改变客户端代码的前提下,为对象的访问提供额外的功能,比如延迟初始化、访问控制、日志记录等。

常见的代理模式的使用场景包括:

  • 远程代理:为一个位于不同地址空间的对象提供本地代表。
  • 虚拟代理:根据需要创建开销较大的对象。
  • 保护代理:控制对原始对象的访问,可以对权限进行控制。
  • 智能引用代理:当访问对象时,执行一些附加操作,比如计数、日志记录等。

定义与结构

模式定义

为其他对象提供一种代理以控制(隔离,使用接口)对这个对象的访问。

结构

在这里插入图片描述
代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。在这个图例中,有几个关键组件和交互过程:

  1. Client(客户端):客户端是发起请求的一方,它不知道真正的实体对象(Subject)是如何被实现和管理的。客户端通过代理(Proxy)来间接地与实体对象交互。

  2. Subject(抽象主题/接口):这是一个定义了RealSubject和Proxy的共通接口的抽象类或接口。它声明了RealSubject和Proxy应该实现的方法,使得客户端能够通过相同的接口与它们交互。

  3. RealSubject(真实主题):这是被代理的对象,它实现了Subject接口。RealSubject包含了执行实际业务逻辑的方法。

  4. Proxy(代理):代理也是一个实现了Subject接口的对象。它持有对RealSubject的引用,并且可以控制对RealSubject的访问。代理可以在将请求传递给RealSubject之前或之后执行额外的操作,如权限检查、日志记录、事务管理等。

交互过程

  • 客户端向代理发送请求(Request())。
  • 代理接收到请求后,可能会执行一些预处理操作(如权限检查)。
  • 然后,代理将请求转发给RealSubject(如realSubject->Request(0);所示,尽管这里的表示方式略显简化)。
  • RealSubject执行实际的业务逻辑并可能返回一个结果。
  • 代理可能会接收到结果并进行后处理,然后将结果返回给客户端。

代理模式的主要优点包括:

  • 减少直接依赖:客户端与RealSubject之间的直接依赖被解耦,提高了系统的灵活性和可维护性。
  • 控制访问:代理可以决定客户端是否可以访问RealSubject,以及何时可以访问。
  • 增加额外的操作:代理可以在请求处理前后执行额外的操作,如日志记录、安全控制等。

这种模式在软件开发中非常有用,特别是当需要控制对某个对象的访问、减少系统组件之间的耦合度或者添加额外的处理逻辑时。

代理模式通常包括以下角色:

  1. Subject(抽象主题):声明了RealSubject和Proxy的公共接口,这样代理就可以用在任何使用RealSubject的地方。
  2. RealSubject(真实主题):定义了代理所代表的真实对象。
  3. Proxy(代理):保存一个引用使得代理可以访问RealSubject。实现Subject接口,代理操作在调用RealSubject之前后可以执行相关操作。

代码推导

下面是一个简单的C++代码示例,展示了代理模式的实现:

Subject接口:

class Subject {
public:
    virtual void request() = 0;
    virtual ~Subject() = default;
};

RealSubject类:

#include <iostream>

class RealSubject : public Subject {
public:
    void request() override {
        std::cout << "RealSubject: Handling request." << std::endl;
    }
};

Proxy类:

class Proxy : public Subject {
private:
    RealSubject* realSubject;

public:
    Proxy() : realSubject(nullptr) {}

    ~Proxy() {
        delete realSubject;
    }

    void request() override {
        if (realSubject == nullptr) {
            realSubject = new RealSubject();
        }
        std::cout << "Proxy: Logging the request." << std::endl;
        realSubject->request();
    }
};

客户端代码:

int main() {
    Proxy proxy;
    proxy.request(); // 实际请求通过代理进行
    return 0;
}

特点

优点:

  1. 控制对象访问:代理模式可以在不改变原始对象的情况下,控制对它的访问。例如,远程代理可以处理网络通信,虚拟代理可以延迟对象的创建。
  2. 增强功能:代理模式允许在不修改客户端代码的情况下增强对象的功能。例如,保护代理可以增加权限控制,智能引用代理可以记录访问日志。
  3. 解耦合:客户端与实际的实现对象解耦,客户端可以通过代理访问不同的实现对象。

缺点:

  1. 性能开销:由于增加了代理层,会造成请求处理的额外开销,尤其是在频繁调用的情况下,可能会影响性能。
  2. 复杂性增加:引入代理模式会增加系统的复杂性,增加类的数量和系统的理解难度。
  3. 潜在问题:如果不恰当地使用代理模式,可能会导致系统的设计不合理,带来维护困难。

应用

  1. 远程代理:为一个位于不同地址空间的对象提供本地代表。例如,在分布式系统中,客户端可以通过远程代理访问远程的对象。
  2. 虚拟代理:根据需要创建开销较大的对象。例如,在图形系统中,虚拟代理可以用于按需加载图像。
  3. 保护代理:控制对原始对象的访问,可以对权限进行控制。例如,在安全系统中,保护代理可以用于控制对敏感对象的访问。
  4. 智能引用代理:当访问对象时,执行一些附加操作,比如计数、日志记录等。例如,智能引用代理可以用于在访问对象时记录日志。

总结

  • 代理模式提供了一种通过代理对象控制对原始对象访问的机制,使得我们可以在不改变客户端代码的情况下,对对象的访问进行控制和增强。尽管引入代理会增加一定的性能开销和系统复杂性,但在适当的场景下使用代理模式,可以显著提高系统的灵活性和可维护性。
  • 增加一层间接层。是软件系统中对许多复杂问题的一种常见解决方法。在面向对象系统中直接使用某些对象会带来很多问题作为间接层的代理对象必须解决这一问题的常见手段。
  • 具体的代理设计模式的实现方法,实现粒度,都相差很大。有些可能对单个对象的做细粒度的控制。比如拷贝。或者写技术。有些可能对组件模块提供抽象代理层在架构层次对对象做代理。
  • 代理模式并不一定要求保持接口完整的一致性。只要能够实现间接控制,有时候损失一些透明性是可以接受的。

实例说明

下面是几个不同类型的代理模式的应用场景,并通过C++代码示例来说明每种场景的实现。

1. 远程代理

远程代理用于访问位于不同地址空间的对象。在这里,我们模拟一个简单的远程方法调用。

#include <iostream>

// Subject interface
class Subject {
public:
    virtual void request() = 0;
    virtual ~Subject() = default;
};

// RealSubject implementation, which might be on a remote server
class RealSubject : public Subject {
public:
    void request() override {
        std::cout << "RealSubject: Handling request." << std::endl;
    }
};

// Proxy implementation that handles communication with the remote RealSubject
class RemoteProxy : public Subject {
private:
    RealSubject* realSubject;

public:
    RemoteProxy() : realSubject(nullptr) {}

    ~RemoteProxy() {
        delete realSubject;
    }

    void request() override {
        if (realSubject == nullptr) {
            std::cout << "RemoteProxy: Creating RealSubject remotely." << std::endl;
            realSubject = new RealSubject();
        }
        std::cout << "RemoteProxy: Forwarding request to RealSubject." << std::endl;
        realSubject->request();
    }
};

// Client code
int main() {
    RemoteProxy proxy;
    proxy.request(); // 实际请求通过代理进行
    return 0;
}

2. 虚拟代理

虚拟代理用于按需创建开销较大的对象。在这里,我们模拟一个按需加载图像的例子。

#include <iostream>

// Subject interface
class Image {
public:
    virtual void display() = 0;
    virtual ~Image() = default;
};

// RealSubject implementation, which represents an actual image
class RealImage : public Image {
private:
    std::string filename;

    void loadFromDisk() {
        std::cout << "Loading " << filename << std::endl;
    }

public:
    RealImage(const std::string& filename) : filename(filename) {
        loadFromDisk();
    }

    void display() override {
        std::cout << "Displaying " << filename << std::endl;
    }
};

// Proxy implementation that creates RealImage only when needed
class ProxyImage : public Image {
private:
    std::string filename;
    RealImage* realImage;

public:
    ProxyImage(const std::string& filename) : filename(filename), realImage(nullptr) {}

    ~ProxyImage() {
        delete realImage;
    }

    void display() override {
        if (realImage == nullptr) {
            realImage = new RealImage(filename);
        }
        realImage->display();
    }
};

// Client code
int main() {
    ProxyImage image("test.jpg");
    image.display(); // Loading and displaying the image
    image.display(); // Displaying the already loaded image
    return 0;
}

3. 保护代理

保护代理用于控制对原始对象的访问,可以对权限进行控制。这里我们模拟一个简单的权限控制例子。

#include <iostream>

// Subject interface
class Subject {
public:
    virtual void request() = 0;
    virtual ~Subject() = default;
};

// RealSubject implementation, which represents an actual service
class RealSubject : public Subject {
public:
    void request() override {
        std::cout << "RealSubject: Handling request." << std::endl;
    }
};

// Proxy implementation that controls access to RealSubject
class ProtectionProxy : public Subject {
private:
    RealSubject* realSubject;
    bool accessGranted;

public:
    ProtectionProxy(bool access) : realSubject(new RealSubject()), accessGranted(access) {}

    ~ProtectionProxy() {
        delete realSubject;
    }

    void request() override {
        if (accessGranted) {
            std::cout << "ProtectionProxy: Access granted." << std::endl;
            realSubject->request();
        } else {
            std::cout << "ProtectionProxy: Access denied." << std::endl;
        }
    }
};

// Client code
int main() {
    ProtectionProxy proxyWithAccess(true);
    proxyWithAccess.request(); // Access granted, forwarding request to RealSubject

    ProtectionProxy proxyWithoutAccess(false);
    proxyWithoutAccess.request(); // Access denied, not forwarding request
    return 0;
}

4. 智能引用代理

智能引用代理在访问对象时执行一些附加操作,如引用计数、日志记录等。这里我们模拟一个记录访问日志的例子。

#include <iostream>
#include <memory>

// Subject interface
class Subject {
public:
    virtual void request() = 0;
    virtual ~Subject() = default;
};

// RealSubject implementation, which represents an actual service
class RealSubject : public Subject {
public:
    void request() override {
        std::cout << "RealSubject: Handling request." << std::endl;
    }
};

// Proxy implementation that logs access to RealSubject
class LoggingProxy : public Subject {
private:
    std::shared_ptr<RealSubject> realSubject;

public:
    LoggingProxy() : realSubject(std::make_shared<RealSubject>()) {}

    void request() override {
        std::cout << "LoggingProxy: Logging request." << std::endl;
        realSubject->request();
    }
};

// Client code
int main() {
    LoggingProxy proxy;
    proxy.request(); // Logging the request and forwarding it to RealSubject
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1961339.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mac电脑流氓软件怎么卸载不了 MacBook删除恶意软件 电脑流氓软件怎么彻底清除

对于Mac用户来说&#xff0c;尽管MacOS系统以其较高的安全性而闻名&#xff0c;但依然不可避免地会遭遇流氓软件或恶意软件的困扰。本文将详细介绍Mac电脑流氓软件怎么卸载&#xff0c;Mac电脑如何移除移除恶意软件&#xff0c;确保你的设备运行安全、流畅。 一、Mac电脑流氓软…

【论文共读】【翻译】【GAN】Generative Adversarial Nets

论文原文地址&#xff1a;https://arxiv.org/pdf/1406.2661 翻译&#xff1a;Generative Adversarial Nets 生成对抗网络 0. 摘要 提出了一种新的对抗过程估计生成模型的框架&#xff0c;其中我们同时训练两个模型&#xff1a;一个是捕获数据分布的生成模型G&#xff0c;另一…

【基础夯实】TCP/IP 协议是怎么控制数据收发

【基础夯实】TCP/IP 协议是怎么控制数据收发 网址输入到页面完整显示&#xff0c;对于此问题&#xff0c;粗略的解释可以分为以下几个步骤&#xff1a; 客户端通过 HTTP 协议对数据进行一次包装通过 DNS 服务器&#xff08;本地无缓存&#xff09;解析网址的 ip 地址通过 TCP…

layui 乱入前端

功能包含 本实例代码为部分傻瓜框架&#xff0c;插入引用layui。因为样式必须保证跟系统一致&#xff0c;所以大部分功能都是自定义的。代码仅供需要用layui框架&#xff0c;但原项目又不是layui搭建的提供解题思路。代码较为通用 自定义分页功能自定义筛选列功能行内编辑下拉、…

【React】详解如何获取 DOM 元素

文章目录 一、基础概念1. 什么是DOM&#xff1f;2. 为什么需要获取DOM&#xff1f; 二、使用 ref 获取DOM元素1. 基本概念2. 类组件中的 ref3. 函数组件中的 ref 三、 ref 的进阶用法1. 动态设置 ref2. ref 与函数组件的结合 四、处理特殊情况1. 多个 ref 的处理2. ref 与条件渲…

跟着丑萌气质狗学习WPF——Style样式

Style样式 1. 用法介绍2. 样式多样性3. 全局样式说明和资源字典的使用 1. 用法介绍 提前写好样式&#xff0c;让他作用于所有按钮 <Window x:Class"WPF_Study_Solution.window3"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmln…

typescript 解构时配置类型

以下三种写法&#xff0c;可以参考&#xff1a; const handleMenuClick ({item, key, keyPath}: {item: Object, key: string, keyPath:string}) > {} const handleMenuClick ({item, key, keyPath}: any) > {} interface SomeObj {item: Objectkey: stringkeyPath:st…

计算机系统操作系统简介

目录 1.计算机系统简介 1.1组成结构 1.2系统软件 1.3冯诺依曼计算机特点 1.4硬件构架 2.硬件的进一步认识 2.1存储器 2.2输入设备 2.3输出设备 2.4CPU组成 2.5线的概念引入 3.操作系统 3.1操作系统简介 3.2操作系统如何管理 3.3库函数和系统调用 1.计算机系统简介…

Linux 用户管理模式

目录 1. 概述 2. 管控级别 3. 用户组管理 4. 用户管理 4.1 创建用户 useradd 4.2 删除用户 userdel ​编辑4.3 查看用户所属组 id 4.4 修改用户所属组 usermod 5. 查看用户/用户组 5.1 查看系统用户 5.2 查看系统用户组 1. 概述 Linux 可以配置多个用户&#xff0c…

ppt中国风背景图片去哪找?附6个优质中国风PPT模板分享!

在这个全球化的时代&#xff0c;中国传统文化元素正在各个领域焕发出新的生机&#xff0c;不管是在时尚、建筑还是平面设计领域&#xff0c;中国风都以其独特的美学魅力吸引着世界的目光。在商业演示和学术报告中&#xff0c;PowerPoint(PPT)作为最常用的工具之一&#xff0c;同…

opencv arm 交叉编译

step1.opencv源码文件夹下新建build-arm目录 step2. cmake图像化配置 cmake-gui .. step3. 选择交叉编译 step4.检索交叉编译链路径 step5. 配置 配置install路径 配置编译、链接选项 添加人脸检测模块 config->generate step6. make编译 built-arm目录下&#xff1a; …

DC-DC转换器电感参数详解

我们对DC-DC转换器的要求以及电感参数中的电感值、公差和电阻进行了介绍。本文中&#xff0c;我们将对电感的其它参数进行详细讲解。 自谐频率&#xff08;SRF&#xff09; 每个电感线圈都有一些联带的分布电容&#xff0c;与电感值一起形成一个有自谐频率的并联谐振回路。对…

探索局域网传输新境界 | 闪电藤 v2.2.7

在这个数字化时代&#xff0c;文件的快速、安全传输是我们日常工作中不可或缺的一部分。今天&#xff0c;电脑天空向大家介绍一款革命性的局域网文件传输工具——闪电藤&#xff0c;它将彻底改变你的文件传输体验。 &#x1f3a8; 界面设计 —— 极简之美 闪电藤采用极简的设…

【自动化测试必学语言】python:语言基础

目录 Python 介绍 语言的分类 注释 单行注释 多行注释 变量 定义变量 使用变量 变量名的命名规范 数据类型 数字类型 非数字类型 type() 函数 input输入 print输出 格式化输出 快捷键(小操作) 运算符 算术运算符 比较运算符 Python 介绍 作者&#xff1a; 吉…

【Java】字符串String类(011)

目录 ♦️API和API帮助文档 ♦️创建String &#x1f38f;直接赋值类 &#x1f38f;new类 &#x1f421;空参类 构造方法&#xff1a; 举例代码&#xff1a; &#x1f421;有参类 构造方法&#xff1a; 举例代码&#xff1a; &#x1f421;字符数组类 构造方法&…

如何借助逻辑数据编织平台实现“数据优先堆栈( DFS )”

一、什么是面向“数据优先”的数据研发平台&#xff1f; 企业在数字化转型的浪潮中&#xff0c;愈发认知到数据作为核心战略资产的重要性。然而&#xff0c;要充分利用数据的价值并非易事。一方面&#xff0c;企业需要投入大量资源来建设和维护复杂的数据基础设施&#xff1b;另…

ref函数

Vue2 中的ref 首先我们回顾一下 Vue2 中的 ref。 ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用&#xff0c;引用指向的就是 DOM 元素&#xff1b;如果用在子组件上&#xff0c;引用就指向组件实例&#xff1…

计算机基础(day1)

1.什么是内存泄漏&#xff1f;什么是内存溢出&#xff1f;二者有什么区别&#xff1f; 2.了解的操作系统有哪些&#xff1f; Windows&#xff0c;Unix&#xff0c;Linux&#xff0c;Mac 3. 什么是局域网&#xff0c;广域网&#xff1f; 4.10M 兆宽带是什么意思&#xff1f;理论…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 整数数组按个位数字排序(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆Coding ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 93 分 最新华为OD机试目录…

使用大型语言模型进行文档解析

动机 多年来&#xff0c;正则表达式一直是我解析文档的首选工具&#xff0c;我相信对于许多技术人员和行业也是如此。尽管正则表达式在某些情况下非常强大&#xff0c;但它们常常在面对真实世界文档的复杂性和多样性时缺少灵活性。 另一方面&#xff0c;大型语言模型提供了一…