十二、结构型(代理模式)
代理模式(Proxy Pattern)
概念
代理模式(Proxy Pattern)是一种结构型设计模式,代理对象在不改变目标对象功能的前提下,通过控制对目标对象的访问,来实现延迟加载、权限控制、日志记录等功能。代理模式可以通过提供一个中介对象,来控制客户端和实际目标对象之间的交互。
应用场景
-
远程代理(Remote Proxy):为位于不同地址空间的对象提供代理,解决远程调用问题。典型的例子是RMI(Remote Method Invocation),通过代理对象进行远程方法调用。
-
虚拟代理(Virtual Proxy):为某些需要较高开销的对象提供代理,延迟其加载和创建。比如,大型图片或文档的加载可以通过虚拟代理来进行,只有当真正需要时才创建实际对象。
-
保护代理(Protection Proxy):用于控制对对象的访问权限。代理对象检查调用者是否具有访问权限,只有在权限允许时,才能访问目标对象。
-
智能引用代理(Smart Reference Proxy):在访问对象时加入一些附加操作,如统计实际对象的引用次数、记录日志、检查锁等。
-
缓存代理(Caching Proxy):代理可以缓存某些计算结果或操作结果,使得后续的相同请求不需要重复计算,提升系统性能。
注意点
- 代理类和实际类必须实现相同的接口:代理类的设计应与目标类保持一致,使得客户端在使用代理类时与使用实际类没有差异。
- 性能开销:尽管代理模式可以增加功能,但也可能增加系统开销,尤其是远程代理涉及到网络传输时。
- 适合复杂的控制场景:代理模式尤其适合在需要控制访问、管理复杂操作、或添加额外处理逻辑的场景中使用。
核心要素
- Subject(抽象主题角色):定义代理类和目标类的共同接口,使得代理类和目标类可以被客户端通过相同的方式调用。
- RealSubject(真实主题角色):定义目标对象,实现真实的业务逻辑。
- Proxy(代理角色):负责控制对真实主题对象的访问,通常会引用一个真实主题对象,并通过实现抽象主题接口来代理其操作。
Java代码完整示例
代码示例:静态代理
// 抽象接口,定义真实主题和代理共同的行为
interface Subject {void request();
}// 真实主题,实现实际的业务逻辑
class RealSubject implements Subject {@Overridepublic void request() {System.out.println("真实主题执行请求");}
}// 代理类,控制对真实主题的访问
class Proxy implements Subject {private RealSubject realSubject;@Overridepublic void request() {// 代理可以在调用真实对象之前执行一些额外操作if (realSubject == null) {realSubject = new RealSubject();}System.out.println("代理:在调用真实对象前的额外操作");realSubject.request();System.out.println("代理:在调用真实对象后的额外操作");}
}// 客户端
public class Client {public static void main(String[] args) {Subject proxy = new Proxy();proxy.request();}
}
输出结果:
代理:在调用真实对象前的额外操作
真实主题执行请求
代理:在调用真实对象后的额外操作
各种变形用法完整示例
-
虚拟代理(Virtual Proxy)
虚拟代理的主要目的是推迟大开销对象的创建,直到需要使用时才创建。典型例子是延迟加载大型图片或文档。代码示例:
interface Image {void display(); }// 真实的图像类,实际加载图片 class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadFromDisk();}private void loadFromDisk() {System.out.println("加载图片: " + fileName);}@Overridepublic void display() {System.out.println("显示图片: " + 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 VirtualProxyClient {public static void main(String[] args) {Image image = new ProxyImage("test.jpg");// 图片首次显示时加载image.display();System.out.println("");// 第二次调用时不需要加载image.display();} }输出结果:
加载图片: test.jpg 显示图片: test.jpg显示图片: test.jpg -
动态代理(Dynamic Proxy)
动态代理是在运行时创建代理类,而不是在编译时创建。在Java中,可以使用java.lang.reflect.Proxy类来实现动态代理,代理类可以动态代理接口定义的所有方法。代码示例:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;// 定义抽象接口 interface Service {void operation(); }// 实现接口的真实类 class RealService implements Service {@Overridepublic void operation() {System.out.println("执行实际操作");} }// 动态代理处理器 class DynamicProxyHandler implements InvocationHandler {private Object target;public DynamicProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("动态代理:在方法执行前");Object result = method.invoke(target, args);System.out.println("动态代理:在方法执行后");return result;} }// 客户端 public class DynamicProxyClient {public static void main(String[] args) {RealService realService = new RealService();Service proxyInstance = (Service) Proxy.newProxyInstance(realService.getClass().getClassLoader(),realService.getClass().getInterfaces(),new DynamicProxyHandler(realService));proxyInstance.operation();} }输出结果:
动态代理:在方法执行前 执行实际操作 动态代理:在方法执行后 -
保护代理(Protection Proxy)
保护代理用于控制访问权限,可以通过代理来检查调用者是否具备权限,只有在通过检查时,才能调用目标对象的方法。代码示例:
interface BankAccount {void deposit(double amount);void withdraw(double amount); }class RealBankAccount implements BankAccount {private double balance;public RealBankAccount(double balance) {this.balance = balance;}@Overridepublic void deposit(double amount) {balance += amount;System.out.println("存款成功,当前余额: " + balance);}@Overridepublic void withdraw(double amount) {if (balance >= amount) {balance -= amount;System.out.println("取款成功,当前余额: " + balance);} else {System.out.println("余额不足,取款失败");}} }// 保护代理类 class ProtectionProxy implements BankAccount {private RealBankAccount realBankAccount;private String userRole;public ProtectionProxy(String userRole, double initialBalance) {this.userRole = userRole;realBankAccount = new RealBankAccount(initialBalance);}@Overridepublic void deposit(double amount) {realBankAccount.deposit(amount);}@Overridepublic void withdraw(double amount) {if ("ADMIN".equals(userRole)) {realBankAccount.withdraw(amount);} else {System.out.println("无权限取款");}} }// 客户端 public class ProtectionProxyClient {public static void main(String[] args) {BankAccount adminAccount = new ProtectionProxy("ADMIN", 1000);adminAccount.withdraw(500);BankAccount userAccount = new ProtectionProxy("USER", 1000);userAccount.withdraw(500);} }输出结果:
取款成功,当前余额: 500.0 无权限取款
总结
代理模式通过引入代理类为目标对象提供额外的功能或控制。它适用于延迟加载、权限控制、日志记录、远程调用等场景。代理模式可以分为静态代理和动态代理,并且具有多种变体,如虚拟代理、保护代理、远程代理等。
相关文章:
十二、结构型(代理模式)
代理模式(Proxy Pattern) 概念 代理模式(Proxy Pattern)是一种结构型设计模式,代理对象在不改变目标对象功能的前提下,通过控制对目标对象的访问,来实现延迟加载、权限控制、日志记录等功能。代…...
使用 python 下载 bilibili 视频
本文想要达成的目标为:运行 python 代码之后,在终端输入视频链接,可自动下载高清 1080P 视频并保存到相应文件夹。 具体可分为两大步:首先,使用浏览器开发者工具 F12 获取请求链接相关信息(根据 api 接口下…...
DevExpress WinForms中文教程:Data Grid - 如何点击获取信息?
在使用DevExpress WinForms的Data Grid之类控件时,可能需要实现自定义用户交互,例如显示数据行的上下文菜单,或者在双击一行时调用编辑表单。在这些情况下,您需要在指定的坐标处标识网格元素。 在本教程中,您将学习如…...
真空牛肉滚揉机的优点:
真空滚揉机是一种用于食品加工的设备,主要用于肉类深加工,如肉食制品和低温火腿的生产。 它通过滚揉、按压和腌制的过程,在真空状态下将原料肉与辅料、添加剂均匀混合,以提高肉制品的质量和口感。 真空滚揉机的工作原理是利…...
【物流配送中心选址问题】基于退火算法混合粒子群算法
课题名称: 基于退火算法混合粒子群算法的物流配送中心选址问题 改进方向:模拟退火算法优化粒子群算法 代码获取方式(付费): 模型说明: 待补充 Matlab仿真结果: 1. 模型优化后的仿真结果 2…...
elasticsearch 8.2 版本账号密码设置及SSL设置
背景:elasticsearch 8.2 设置账号密码-CSDN博客 failed to load SSL configuration does not contain any trusted certificate entries [2024-10-08T17:06:53,704][ERROR][o.e.b.ElasticsearchUncaughtExceptionHandler] [node-1] uncaught exception in thread [main] org…...
git gui基本使用
一、图形化界面 二、创建新项目 创建文件,加入暂存区,提交到版本库 三、创建分支 四、合并分支 1.切换至master 五、更新分支 六、解决冲突 修改冲突,加入暂存区,提交到版本库 七、远程创建库 Gitee - 基于 Git 的代码托管和研…...
从automaxprocs库浅窥Linux容器的资源控制
automaxprocs能够自动调整Go程序中的Goroutine数量,以充分利用系统资源并提高程序的性能。 automaxprocs通过读取系统信息,如CPU核心数和Cgroups限制,来动态调整Goroutine的数量 automaxprocs获取CPU限额的关键方法在 // CPUQuotaToGOMAXP…...
AI 读文献(二):综述论文10倍速读和整理
我是娜姐 迪娜学姐 ,一个SCI医学期刊编辑,探索用AI工具提效论文写作和发表。 上一篇娜姐讲了research研究论文的速度框架和效果, AI阅读研究论文,这个方法10倍速提升效率还不损失关键信息! 学员们反馈效果很好&#x…...
【AAOS】Android Automotive 10模拟器源码下载及编译
源码下载 repo init -u https://android.googlesource.com/platform/manifest -b android-10.0.0_r47 repo sync -c --no-tags --no-clone-bundle 源码编译 source build/envsetup.sh lunch aosp_car_x86_64-userdebug make -j8 运行效果 emualtor Cluster Home Map All …...
前端开发攻略---使用css实现滚动吸附效果
实现代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title><style>…...
解析 MySQL 查询优化:提升性能的十个关键策略
1. 避免全表扫描 当查询的数据量非常大时,全表扫描的效率会很低。应尽量通过在WHERE和ORDER BY涉及的列上创建索引,避免全表扫描。索引就像一本书的目录,可以快速定位到需要的数据,而不用从头开始逐页查找。 示例: 如…...
QT--QPushButton设置文本和图标、使能禁能、信号演示
按钮除了可以设置显示文本之外,还可以设置图标 文本 可以获取和设置按钮上显示的文本 // 获取和设置按钮的文本 QString text() const void setText(const QString &text)该属性,既可以在 Qt 设计师右侧的属性窗口中修改,也可以在代码…...
PostgreSQL学习笔记六:模式SCHEMA
模式(Schema) PostgreSQL中的模式(Schema)是一个命名的数据库对象集合,包括表、视图、索引、数据类型、函数、存储过程和操作符等。模式的主要作用是组织和命名空间数据库对象,使得同一个数据库中可以包含…...
基础IO -- 理解文件(1)
目录 一:回顾文件 二:加深对文件的理解 1.概念 2.以w写方式打开 3.以a追加方式打开 4.重定向 一:回顾文件 以前学习过在C语言中的文件操作, 但那根本是不足以理解文件的,即站在语言角度是不可能理解文件的 我们要…...
golang包管理
package 在工程化的Go语言开发项目中,Go语言的源码复用是建立在包(package)基础之上的。本文介绍了Go语言中如何定义包、如何导出包的内容及如何导入其他包。 包与依赖管理 本章学习目标 掌握包的定义和使用掌握init初始化函数的使用掌握…...
outlook 添加企业邮箱账号出现 553 authentication is required 错误解决
系统报错如下 问题原因 发件服务器身份验证设置错误,或者未勾选发送服务器验证的选项。 解决方案 Outlook客户端 本文以Outlook 2016为例,具体操如下: 1、在Outlook客户端的电子邮件设置窗口中,单击其他设置; 2、…...
一个开源可本地部署的英文翻译服务----EnToZhAPI
EnToZhAPI项目简介 项目背景 提供本地化的英文翻译服务API。支持单句翻译请求或者批量翻译请求。支持建立查询词汇表。 项目架构 前端:使用原生js,使用MDB作为CSS框架。django模板引擎渲染可视化界面。 后端:使用waitress作为后端服务器…...
【unity】编辑器扩展——在OnValidate中创建、删除游戏物体
我们知道在OnValidate中创建游戏物体会发出警告,删除游戏物体会报错。 所以我们使用协程,将开始动作的信号放在OnValidate中,将动作的执行放在帧结尾。 参考代码如下: using System.Collections; using UnityEngine;public clas…...
学习记录:js算法(六十四):最后一块石头的重量
文章目录 最后一块石头的重量思路一思路二 最后一块石头的重量 有一堆石头,每块石头的重量都是正整数。 每一回合,从中选出两块 最重的 石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x < y。那么粉碎的可能结果如…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
