设计模式16-代理模式

设计模式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 imageimage.display(); // Displaying the already loaded imagereturn 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 RealSubjectProtectionProxy proxyWithoutAccess(false);proxyWithoutAccess.request(); // Access denied, not forwarding requestreturn 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 RealSubjectreturn 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java面试八股之Spring如何解决循环依赖

Spring如何解决循环依赖 在Spring框架中&#xff0c;循环依赖问题通常发生在两个或多个Bean相互依赖的情况下。Spring为了解决循环依赖问题&#xff0c;采用了不同的策略&#xff0c;这些策略主要取决于Bean的作用域以及依赖注入的方式。下面是一些关键点&#xff1a; 单例Be…

centos安装python 3.9

centos安装python 3.9 1. 准备工作 安装必要的构建工具和依赖项&#xff1a; sudo yum groupinstall "Development Tools" sudo yum install -y zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel …

轻量级服务器资源监控平台Beszel

什么是 Beszel &#xff1f; Beszel 是一个轻量级平台&#xff0c;借助 Beszel&#xff0c;可以访问 CPU 和内存使用情况的历史数据&#xff0c;以及 Docker 容器指标&#xff08;例如特定于容器的 CPU 和内存统计信息&#xff09;。还能收到针对潜在问题的可自定义警报通知&am…

【Golang 面试 - 进阶题】每日 3 题(八)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…

基于Django与spark的国漫推荐系统

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍每文一语 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 近年来&#xff0c;随着互联网的蓬勃发展&#xff0c;企事业单位对信息的管理提…

C#知识|文件与目录操作:对象的创建、保存、读取

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 面向对象编程的特点就是一切皆对象&#xff0c;操作的也是对象&#xff0c;本节学习文件与目录操作中&#xff0c;对象的保存&#xff1b; 以下为学习笔记。 01 对象的特点 ①&#xff1a;对象运行在内存中&#xff…

二刷代码随想录训练营Day 11| 150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素、总结

1.逆波兰表达式 题目链接/文章讲解/视频讲解&#xff1a;代码随想录 代码&#xff1a; class Solution { public:int evalRPN(vector<string>& tokens) {stack<long long> st;for(int i 0; i < tokens.size(); i){if(tokens[i] "" || tokens[i…

vue里给img的src绑定数据失效

起因 在v-for遍历数据时想要通过给img的src单向绑定 图片路径时出现问题 解决过程 上网查说是webpack构建时识别不到&#xff0c;直接不单绑数据&#xff0c;写死试试看 解决方案 直接require导入图像文件模块

热门超声波清洗机有哪些?小型超声波清洗机推荐

在繁忙的工作和生活中&#xff0c;许多人常常会因为种种原因忽略日常的小事&#xff0c;比如忘记清洁手表、眼镜、首饰等常用物品。实际上&#xff0c;这些物品表面不仅积累了灰尘和污垢&#xff0c;特别是跟眼部朝夕相处的眼镜&#xff0c;还可能滋生各种致病细菌&#xff0c;…

【数据分享】《内蒙古省统计年鉴》2000-2023

而今天要限时免费分享的数据就是2000-2023年间出版的《内蒙古省统计年鉴》并以多格式提供免费下载。&#xff08;无需分享朋友圈即可获取&#xff09; 数据介绍 位于中国北部的内蒙古自治区&#xff0c;以其独特的地理和文化特性&#xff0c;成为中国经济发展的重要组成部…

京东科技集团将在香港发行与港元1:1挂钩的加密货币稳定币

据京东科技集团旗下公司京东币链科技(香港)官网信息&#xff0c;京东稳定币是一种基于公链并与港元(HKD) 1:1挂钩的稳定币&#xff0c;将在公共区块链上发行&#xff0c;其储备由高度流动且可信的资产组成&#xff0c;这些资产安全存放于持牌金融机构的独立账户中&#xff0c;通…

工具(1)—截屏和贴图工具snipaste

演示和写代码文档的时候&#xff0c;总是需要用到截图。在之前的流程里面&#xff0c;一般是打开WX或者QQ&#xff0c;找到截图工具。但是尴尬的是&#xff0c;有时候&#xff0c;微信没登录&#xff0c;而你这个时候就在写文档。为了截个图&#xff0c;还需要启动微信&#xf…

数据透视表(二)

文章目录 导入外部数据源创建数据透视表Query 工具下的数据透视表创建如何统计业绩成交情况创建组利用函数构建辅助列创建组手动创建多样分组创建组区间统计创建组按年月日统计数据透视表的多种统计方法计算字段 导入外部数据源创建数据透视表 点击数据选项卡下数据-获取外部数…

环境搭建-Windows系统搭建Docker

Windows系统搭建Docker 一、系统虚拟化1.1 启用虚拟化2.2 启用Hyper-v并开启虚拟任务 三、安装WSL3.1 检验安装3.2 安装WSL 四、Docker安装4.1 Docker安装包下载4.2 Docker安装4.3 运行docker Desktop 五、Docker配置5.1 打开Docker配置中心5.2 配置Docker国内镜像 六、使用 一…

马斯克的Memphis AI超级计算中心:全球最强AI训练集群的诞生

引言 近期&#xff0c;马斯克宣布其最新的Memphis AI超级计算中心正式启动&#xff0c;这一新闻引发了科技界的广泛关注。该中心配备了10万块液冷H100 GPU&#xff0c;成为全球最强大的AI训练集群。本文将深入探讨Memphis AI超级计算中心的建设过程、技术细节、以及其对未来人…

昇思25天学习打卡营第24天|基于MobileNetv2的垃圾分类案例:从数据准备到导出模型文件

目录 MindSpore 版本配置及相关数据集与预训练权重文件下载 基于 MindSpore 的垃圾分类数据集创建与配置 MobileNetV2 模型的构建与相关类定义 基于 MindSpore 的 MobileNetV2 模型训练与测试代码分析 基于 MobileNetV2 模型的图像推理代码分析 MobileNetV2 模型的构建、加…

C语言——设计TVM(地铁自动售票机)机软件。

输入站数&#xff0c;计算费用&#xff0c;计费规则&#xff0c;6站2元&#xff0c;7-10站3元&#xff0c;11站以上为4元。 输入钱数&#xff0c;计算找零(找零时优先找回面额大的钞票)&#xff0c;找零方式为各种面额张数&#xff0c;可识别面额&#xff1a; 100,50,20,10,5,1…

yandex图标点选验证码YOLOV8识别案例

注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架 某yandex图标点选验证码如下: 使用过yolov8的小伙伴可能都知道,这种直接打个标注,基本上就可以了,至于问题图片由于不能很好的切割做分类,所以干脆也做成目标…

[Bugku] web-CTF靶场详解!!!

平台为“山东安信安全技术有限公司”自研CTF/AWD一体化平台&#xff0c;部分赛题采用动态FLAG形式&#xff0c;避免直接抄袭答案。 平台有题库、赛事预告、工具库、Writeup库等模块。 ------------------------------- Simple_SSTI_1 启动环境&#xff1a; 页面提示传入参数f…

【Linux】make/Makefile的理解

1.make是一个命令&#xff0c;makefile是一个文件, 依赖关系和依赖方法. a.快速使用一下 i.创建一个Makefile文件(首字母也可以小写) b.依赖关系和依赖方法 i.依赖关系: 我为什么要帮你? mybin:mytest.c ii.依赖方法: 怎么帮? gcc -o mybin mytest.c make之前要注意先创建…