设计模式- 代理模式(Proxy Pattern)结构|原理|优缺点|场景|示例

                                    设计模式(分类)        设计模式(六大原则)   

    创建型(5种)        工厂方法         抽象工厂模式        单例模式        建造者模式        原型模式

    结构型(7种)        适配器模式        装饰器模式        代理模式        ​​​​​​外观模式      桥接模式        组合模式       享元模式

    行为型(11种)       策略模式        模板方法模式        观察者模式        迭代器模式        责任链模式        命令模式

                                   备忘录模式          状态模式          访问者模式        中介者模式    


代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象(被代理对象)提供一个代理对象,并由代理对象控制对被代理对象的访问。代理模式通过引入代理对象来间接访问目标对象,从而实现对目标对象的增强、控制访问权限、远程访问等功能。代理模式的关键在于代理类与目标类具有相同的接口,客户端可以透明地使用代理对象代替目标对象。

模式结构

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

  1. 抽象主题(Subject):定义了目标对象和代理对象共有的接口,这样在任何使用目标对象的地方都可以使用代理对象。

  2. 真实主题(Real Subject):也称为被代理对象,实现了抽象主题接口,包含具体业务逻辑。

  3. 代理(Proxy):也实现了抽象主题接口,其内部持有真实主题的引用。代理对象在实现接口方法时,可以选择调用真实主题的方法,也可以在调用前后添加额外的操作,如预处理、后处理、访问控制、日志记录等。

工作原理

  • 客户端:通过代理对象来调用目标对象的方法,对客户端而言,代理对象与真实主题对象在接口上是透明的,客户端无需关心具体使用的是哪个对象。
  • 代理:实现了与真实主题相同的接口,内部持有真实主题的引用。代理对象在接收到客户端请求时,可以选择直接调用真实主题的方法,也可以在调用前后添加额外的操作。
  • 真实主题:实现了抽象主题接口,包含具体的业务逻辑。在代理模式中,真实主题通常不直接暴露给客户端,而是通过代理对象间接访问。

代理模式的分类

  1. 静态代理:代理类在编译时就确定,由程序员创建代理类或使用工具生成。静态代理的优点是直观、简单,缺点是需要为每个具体主题都创建一个对应的代理类,增加了代码量和维护成本。

  2. 动态代理:代理类在运行时动态生成,如Java中的JDK动态代理和CGLIB库。动态代理的优点是可以减少代码量,只需要编写一个通用的代理类生成器,适用于需要为大量类生成代理的情况。

优缺点

优点
  • 职责清晰:代理对象与真实主题对象职责明确,代理对象负责控制访问、增强功能等,真实主题对象专注于业务逻辑。
  • 扩展性好:通过代理模式可以方便地添加新的功能,如访问控制、日志记录等,而无需修改真实主题。
  • 保护真实主题:通过代理对象可以隐藏真实主题的实现细节,提供额外的安全性和控制。
缺点
  • 增加复杂性:引入代理对象会使系统变得更复杂,增加了额外的类和对象关系。
  • 性能损耗:代理模式可能会带来一定的性能损耗,尤其是在代理对象执行额外操作的情况下。

适用场景

  • 需要为对象增加额外功能:如添加日志、事务管理、访问控制等,而又不想修改对象本身。
  • 需要对对象的访问进行控制:如远程访问、延迟加载、资源优化等。
  • 需要隐藏对象的复杂性:通过代理对象对外提供简洁的接口,隐藏真实主题的复杂实现。

代码示例(以Java为例,展示静态代理)

// 抽象主题(接口)
interface Image {void display();
}// 真实主题(被代理对象)
class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadFromDisk(fileName);}private void loadFromDisk(String fileName) {System.out.println("Loading image from disk: " + fileName);}@Overridepublic void display() {System.out.println("Displaying image: " + fileName);}
}// 代理
class ProxyImage implements Image {private RealImage realImage;private String fileName;public ProxyImage(String fileName) {this.fileName = fileName;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(fileName);}realImage.display();}
}// 客户端代码
public class Client {public static void main(String[] args) {Image proxyImage = new ProxyImage("large-image.jpg");proxyImage.display();  // 输出:Loading image from disk: large-image.jpg, Displaying image: large-image.jpgSystem.out.println("\nDisplaying image again:");proxyImage.display();  // 输出:Displaying image: large-image.jpg}
}

在这个Java示例中:

  • Image接口作为抽象主题,定义了显示图像的方法。
  • RealImage类是需要被代理的真实主题,实现了Image接口,包含了从磁盘加载图像和显示图像的业务逻辑。
  • ProxyImage类作为代理,实现了Image接口,内部持有RealImage对象的引用。ProxyImage在实现display()方法时,首先检查RealImage对象是否已经加载,如果没有则先加载图像,然后调用RealImagedisplay()方法显示图像。这样实现了延迟加载的功能,只有在真正需要显示图像时才从磁盘加载,提高了性能。

客户端代码创建ProxyImage对象,并通过代理对象调用display()方法,实现了对真实主题对象的延迟加载。客户端无需关心代理对象的实现细节,只需面向Image接口编程。

 代码示例(以Python为例)

# 抽象主题(接口)
class Image:def display(self):raise NotImplementedError("Subclasses must implement this method")# 真实主题(被代理对象)
class RealImage(Image):def __init__(self, filename):self.filename = filenameself.load_from_disk()def load_from_disk(self):print(f"Loading image from disk: {self.filename}")def display(self):print(f"Displaying image: {self.filename}")# 代理
class ProxyImage(Image):def __init__(self, filename):self.filename = filenameself.real_image = Nonedef display(self):if not self.real_image:self.real_image = RealImage(self.filename)self.real_image.display()# 客户端代码
def main():proxy_image = ProxyImage("large-image.jpg")proxy_image.display()  # 输出:Loading image from disk: large-image.jpg, Displaying image: large-image.jpgprint("\nDisplaying image again:")proxy_image.display()  # 输出:Displaying image: large-image.jpgif __name__ == "__main__":main()

在这个Python示例中:

  • Image类作为抽象主题,定义了显示图像的display()方法。
  • RealImage类是需要被代理的真实主题,继承自Image类,包含了从磁盘加载图像和显示图像的业务逻辑。
  • ProxyImage类作为代理,同样继承自Image类,内部持有RealImage对象的引用。ProxyImage在实现display()方法时,首先检查RealImage对象是否已经加载,如果没有则先加载图像,然后调用RealImagedisplay()方法显示图像。这样实现了延迟加载的功能,只有在真正需要显示图像时才从磁盘加载,提高了性能。

客户端代码创建ProxyImage对象,并通过代理对象调用display()方法,实现了对真实主题对象的延迟加载。客户端无需关心代理对象的实现细节,只需面向Image接口编程。

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

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

相关文章

Python构建学生信息管理系统:网站路由补充和首次运行

在之前的内容中,我们已经完成了学生信息管理系统(Student Information Management System, SIMS)的需求分析、环境搭建、数据库创建、项目结构的初始化,以及运行。正常做下来的朋友,会发现项目运行后输入http://127.0.…

vulfocus靶场thinkphp命令执行cve-2018-1002015

thinkPHP 5.0.x版本和5.1.x版本中存在远程代码执行漏洞,该漏洞源于ThinkPHP在获取控制器名时未对用户提交的参数进行严格的过滤。远程攻击者可通过输入‘\’字符的方式调用任意方法利用该漏洞执行代码 开启靶场: 使用工具: think…

使用微软Phi-3-mini模型快速创建生成式AI应用

微软Phi-3大语言模型是微软研究院推出的新一代系列先进的小语言模型。Phi-3系列包括phi-3-mini、phi-3-small和phi-3-medium三个不同规模的版本。这些模型在保持较小的参数规模的同时,通过精心设计的训练数据集和优化的算法,实现了与大型模型相媲美的语言…

VaR(Value at Risk)模型代码

Value at Risk(VaR)是一种用于衡量投资组合可能损失的风险的模型。它可以帮助投资者评估他们面临的潜在风险,并做出相应的风险管理决策。以下是一个简单的VaR模型案例。 假设一个投资组合由两个资产组成:股票A和股票B。股票A的市…

Edge下载文件提示无法安全下载的解决方法

问题描述:最近Edge在下载文件时总是提示:无法安全下载,本文记录一下解决方法。 提示截图: 解决方式一: 1. 点击下图红框的三个点,选择保留 2. 选择仍然保留 解决方式二: 第一种方式每下载一次…

JavaScript、Java、C#标记过时方法

JavaScript、Java、C#标记过时方法 在JavaScript、Java和C#中,可以使用特定的注解或标记来表示一个方法是不推荐的,以便在使用该方法时发出警告或提示。虽然没有专门用于标记不推荐方法的内置标记,但是可以结合使用deprecated、[Obsolete]等…

✅为什么MySQL默认使用RR隔离级别?

对于数据库的默认隔离级别,Oracle默认的隔离级别是 RC,而MySQL默认的隔离级别是 RR。 那么,你知道为什么Oracle选择RC作为默认级别,而MySQL要选择RR作为默认的隔离级别吗? Oracle的隔离级别 Oracle支持ANSI/ISO SQL…

逝去的韶光

韶光易逝,岁月难留。春夏之交,正是时光交替的节点,仿佛一切都在默默地诉说着曾经的往事。我站在这个特殊的时刻,不禁想起那些已经远去的日子。 阳光穿过树梢,斑驳地洒在小径上。微风拂过,树叶轻轻摇曳&…

【OpcUA开发笔记 3】Open62541证书登录方式

前言: OpcUA的登录方式有3种,分别是匿名,用户名+密码,证书。其中前两个比较简单,我们就从最复杂的说起,前两个顺带说下也就会了,属于抛砖引玉讲述解决思路,非保姆式教程。 材料:open62541-1.4.0,cmake 3.29.2,openssl 3.3.0.9,visual studio2022,python3.8.6 一、…

HTB靶场 Perfection

端口 打开了ssh和http服务 访问 Perfection靶机的网站 是一个根据权重计算总成绩的网站 Wappalyzer查看网页用的什么编写搭建的 抓包看一下是怎么工作的 发送,,返回的结果 如果我在 类别 后面多加一句命令 就会出现提示 恶意输入阻止 大概率有命令注入 通过插件…

【第34天】SQL进阶-SQL高级技巧-Window Funtion(SQL 小虚竹)

回城传送–》《100天精通MYSQL从入门到就业》 文章目录 零、前言一、练习题目二、SQL思路初始化数据什么是Window Funtion窗口函数的分类语法结构第一种写法:第二种写法:实战体验序号函数:row_number()序号函数:rank()序号函数:dense_rank()

动手学深度学习——pandas

1. 简介 作用:对数据进行预处理,是数据科学常使用的库。 支持多种数据格式读取: CSV/Excel/SQL/JSON/HTML数据清洗:处理缺失值、重复值、异常值、数据转换合并数据过滤:灵活的索引、切片、筛选功能,方便选…

2024最新版JavaScript逆向爬虫教程-------基础篇之JavaScript密码学以及CryptoJS各种常用算法的实现

目录 一、密码学介绍1.1 为什么要学密码学?1.2 密码学里面学哪一些 二、字符编码三、位运算四、Hex 编码与 Base64 编码4.1 Hex 编码4.2 Base64 编码 五、消息摘要算法5.1 简介5.2 JS中的MD5、SHA、HMAC、SM3 六、对称加密算法6.1 介绍6.2 加密模式和填充方式6.3 CryptoJS 中D…

元宇宙虚拟空间的角色状态更新(七)

前言 该文章主要讲元宇宙虚拟空间的角色状态更新,基本核心技术点 角色状态更新 对角色设置一个位置判断(从中心点向下投射一射线确定角色的位置) character.feetRaycast(); feetRaycast的start获取碰撞体的位置,end射线结束的…

Linux驱动开发:掌握SPI通信机制

目录标题 1、SPI简介2、SPI通信机制3、Linux内核中的SPI支持4、SPI核心API5、SPI控制器驱动6、SPI设备驱动 7、编写SPI设备驱动8、调试SPI驱动 在Linux驱动开发中,串行外设接口(SPI)是一种常见的高速全双工通信协议,用于连接处理器和各种外设。本文将深入…

QFD赋能人工智能:打造智能化需求分析与优化新纪元

在科技飞速发展的今天,人工智能(AI)已经渗透到我们生活的方方面面。然而,如何让AI更加贴合用户需求,提供更加精准和个性化的服务?这成为了一个亟待解决的问题。质量功能展开(Quality Function Deployment,简…

区分stable diffusion中的通道数与张量维度

区分stable diffusion中的通道数与张量形状 1.通道数:1.1 channel 31.2 channel 4 2.张量形状2.1 3D 张量2.2 4D 张量2.2.1 通常2.2.2 stable diffusion 3.应用3.1 问题3.2 举例3.3 张量可以理解为多维可变数组 前言:通道数与张量形状都在数值3和4之间…

Linux的FTP服务

目录 1.什么是FTP服务? 2.FTP的工作原理和流程 1 主动模式 2 被动模式 3.搭建和配置FTP服务 1 下载服务包、备份配置文件 2 修改配置文件​编辑 3 匿名访问测试 4 设置黑白命令 1.什么是FTP服务? FTP(file Transfer Protocol&#…

Vue3 实现 Three.js粒子特效

效果 <template><div id"waves" /> </template><script setup> import { ref, onMounted, onUnmounted } from "vue"; import * as THREE from "three";const amountX ref(50); const amountY ref(50); const color …

QT学习之窗口基本设置

this->setWindowTitle("二代证测试工具"); // 设置窗口名this->setWindowIcon(QIcon("logo.jpg")); // 设置角标this->setFixedSize(900, 730); // 设置窗口大小设置exe图标 .rc文件代码中设置如下