【软件设计】常用设计模式--代理模式
文章目录
- 代理模式(Proxy Pattern)
- 1. 概念
- 2. 模式结构
- 3. UML 类图
- 4.实现方式
- C# 示例
- 步骤1:定义主题接口
- 步骤2:实现真实主题
- 步骤3:实现代理类
- 步骤4:客户端使用代理模式
- 输出结果:
- Java 示例
- 步骤1:定义主题接口
- 步骤2:实现真实主题
- 步骤3:实现代理类
- 步骤4:客户端使用代理模式
- 输出结果:
- 5. 代理模式的类型
- 5.1 虚拟代理
- 5.2 远程代理
- 实现步骤
- 步骤1:定义主题接口
- 步骤2:实现真实主题
- 步骤3:实现远程代理
- 步骤4:客户端使用远程代理
- 5.3 保护代理
- 5.4 智能代理
- 实现步骤
- 步骤1:定义主题接口
- 步骤2:实现真实主题
- 步骤3:实现智能代理
- 步骤4:客户端使用智能代理
- 5.5 应用场景
- 6. 优点
- 7. 缺点
- 8. 代理模式应用场景
- 9.代理模式变体
- 9.1 虚拟代理(Virtual Proxy)
- 实现步骤
- 步骤1:定义主题接口
- 步骤2:实现真实主题
- 步骤3:实现虚拟代理
- 步骤4:客户端使用虚拟代理
- 应用场景
- 9.2 保护代理(Protection Proxy)
- 实现步骤
- 步骤1:定义主题接口
- 步骤2:实现真实主题
- 步骤3:实现保护代理
- 步骤4:客户端使用保护代理
- 应用场景
- 9.3 缓存代理(Caching Proxy)
- 实现步骤
- 步骤1:定义主题接口
- 步骤2:实现真实主题
- 步骤3:实现缓存代理
- 步骤4:客户端使用缓存代理
- 应用场景
- 10.总结
代理模式(Proxy Pattern)
1. 概念
代理模式是一种结构型设计模式,它为另一个对象提供了一个替身或占位符,以控制对该对象的访问。代理可以代替原对象执行操作、控制访问权限、延迟加载等。这种模式的关键在于代理对象和被代理对象实现相同的接口,以确保它们可以互换。
2. 模式结构
代理模式的核心角色包括:
- 主题(Subject):定义了代理对象和真实对象的公共接口。
- 真实主题(RealSubject):实际的业务逻辑类,代理对象通过控制对它的访问来扩展功能。
- 代理(Proxy):持有对
RealSubject的引用,并可以在调用前后对其操作进行控制或扩展。
3. UML 类图
4.实现方式
C# 示例
步骤1:定义主题接口
public interface ISubject
{void Request();
}
步骤2:实现真实主题
public class RealSubject : ISubject
{public void Request(){Console.WriteLine("RealSubject: Handling Request.");}
}
步骤3:实现代理类
public class Proxy : ISubject
{private RealSubject _realSubject;public void Request(){if (_realSubject == null){_realSubject = new RealSubject();}Console.WriteLine("Proxy: Controlling access before forwarding the request.");_realSubject.Request();}
}
步骤4:客户端使用代理模式
class Program
{static void Main(string[] args){ISubject proxy = new Proxy();proxy.Request();}
}
输出结果:
Proxy: Controlling access before forwarding the request.
RealSubject: Handling Request.
Java 示例
步骤1:定义主题接口
public interface Subject {void request();
}
步骤2:实现真实主题
public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}
步骤3:实现代理类
public class Proxy implements Subject {private RealSubject realSubject;@Overridepublic void request() {if (realSubject == null) {realSubject = new RealSubject();}System.out.println("Proxy: Controlling access before forwarding the request.");realSubject.request();}
}
步骤4:客户端使用代理模式
public class Main {public static void main(String[] args) {Subject proxy = new Proxy();proxy.request();}
}
输出结果:
Proxy: Controlling access before forwarding the request.
RealSubject: Handling request.
5. 代理模式的类型
5.1 虚拟代理
虚拟代理用于控制资源密集型对象的实例化,常用于延迟加载(Lazy Initialization)场景。代理类在实际使用时才实例化真实对象,从而节省系统资源。
- 示例:当一个图像很大且加载时间较长时,使用虚拟代理可以延迟图像的加载,只有当图像真正需要显示时才进行加载。
public class ImageProxy : IImage
{private RealImage _realImage;private string _fileName;public ImageProxy(string fileName){_fileName = fileName;}public void Display(){if (_realImage == null){_realImage = new RealImage(_fileName);}_realImage.Display();}
}
5.2 远程代理
远程代理为位于不同地址空间的对象(如通过网络通信的对象)提供代理。客户端通过代理访问远程服务器上的对象,而不直接处理复杂的通信逻辑。
- 示例:当客户端需要访问远程的Web服务或数据库时,使用远程代理可以将网络通信的复杂性隐藏在代理类中。
实现步骤
步骤1:定义主题接口
与真实对象和代理对象共享相同的接口,以便客户端可以通过代理访问。
public interface Subject {void request();
}
步骤2:实现真实主题
真实对象实现了主题接口,并包含了实际的业务逻辑。
public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}
步骤3:实现远程代理
远程代理通常会处理网络通信的细节,比如使用HTTP、Socket等。它会将请求发送到远程服务器,接收响应并返回给客户端。
import java.io.*;
import java.net.*;public class RemoteProxy implements Subject {private String serverAddress;public RemoteProxy(String serverAddress) {this.serverAddress = serverAddress;}@Overridepublic void request() {try {Socket socket = new Socket(serverAddress, 8080);PrintWriter out = new PrintWriter(socket.getOutputStream(), true);BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out.println("Request from Remote Proxy");String response = in.readLine();System.out.println("Response from Real Subject: " + response);in.close();out.close();socket.close();} catch (IOException e) {e.printStackTrace();}}
}
步骤4:客户端使用远程代理
客户端通过远程代理调用真实主题的功能。
public class Client {public static void main(String[] args) {Subject proxy = new RemoteProxy("localhost");proxy.request();}
}
服务器端示例
服务器端接收请求并返回响应:
import java.io.*;
import java.net.*;public class Server {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("Server is running...");while (true) {Socket clientSocket = serverSocket.accept();PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));String request = in.readLine();System.out.println("Received: " + request);out.println("Handled by Real Subject");in.close();out.close();clientSocket.close();}}
}
5.3 保护代理
保护代理用于控制对原始对象的访问,主要是限制某些客户端的权限。代理会根据访问者的权限决定是否可以访问真实对象。
- 示例:在访问控制系统中,代理可以根据用户的角色决定是否授予对特定资源的访问权。
public class ProtectedProxy : ISubject
{private RealSubject _realSubject;private string _userRole;public ProtectedProxy(string userRole){_userRole = userRole;}public void Request(){if (_userRole == "Admin"){_realSubject = new RealSubject();_realSubject.Request();}else{Console.WriteLine("Access Denied: You don't have permission to perform this operation.");}}
}
5.4 智能代理
智能代理可以在真实对象操作的前后执行一些附加操作,例如记录日志、统计调用次数、缓存结果等。
- 示例:在Web应用程序中,智能代理可以用于记录每个请求的处理时间。
public class LoggingProxy : ISubject
{private RealSubject _realSubject;public void Request(){Console.WriteLine("Logging: Before executing the request.");if (_realSubject == null){_realSubject = new RealSubject();}_realSubject.Request();Console.WriteLine("Logging: After executing the request.");}
}
实现步骤
步骤1:定义主题接口
与之前相同,定义一个公共接口。
public interface Subject {void request();
}
步骤2:实现真实主题
实现主题接口的真实对象。
public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}
步骤3:实现智能代理
智能代理在调用真实对象的请求方法前后执行一些附加操作,比如记录日志或计算执行时间。
public class SmartProxy implements Subject {private RealSubject realSubject;public SmartProxy() {this.realSubject = new RealSubject();}@Overridepublic void request() {System.out.println("SmartProxy: Logging before request.");long startTime = System.currentTimeMillis();realSubject.request();long endTime = System.currentTimeMillis();System.out.println("SmartProxy: Logging after request. Execution time: " + (endTime - startTime) + " ms");}
}
步骤4:客户端使用智能代理
客户端通过智能代理调用真实主题。
public class Client {public static void main(String[] args) {Subject proxy = new SmartProxy();proxy.request();}
}
5.5 应用场景
远程代理
场景:在分布式系统中,客户端需要访问远程服务,远程代理负责处理网络通信和请求转发。
应用:RPC(远程过程调用)、RESTful API等场景。
智能代理
场景:需要对方法调用进行监控、统计或其他增强功能,智能代理可以提供附加的处理逻辑。
应用:日志记录、性能监控、缓存管理等场景。
6. 优点
- 控制对象访问:代理模式可以控制对真实对象的访问,添加权限控制、延迟加载、网络通信等功能。
- 节省系统资源:虚拟代理可以在对象真正需要时才创建,从而节省资源。
- 增强功能:代理可以在真实对象执行操作前后添加额外的功能,如日志记录、缓存等。
7. 缺点
- 增加复杂性:由于引入了代理类,系统变得更加复杂,增加了类的数量。
- 性能开销:代理可能导致额外的开销,特别是在处理远程调用或过度使用智能代理时。
8. 代理模式应用场景
- 远程代理:当需要访问远程对象时,可以使用远程代理隐藏通信的细节。
- 虚拟代理:当需要延迟加载资源密集型对象时,可以使用虚拟代理。
- 访问控制:当需要控制对某些资源或对象的访问权限时,保护代理是一个理想的选择。
- 性能优化:使用智能代理可以在不改变原有业务逻辑的情况下,优化性能或增加功能。
9.代理模式变体
9.1 虚拟代理(Virtual Proxy)
虚拟代理用于延迟加载资源密集型对象的实例化,直到需要时才创建真实对象。这样可以节省系统资源,避免不必要的开销。
实现步骤
步骤1:定义主题接口
public interface Image {void display();
}
步骤2:实现真实主题
public class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadImageFromDisk();}private void loadImageFromDisk() {System.out.println("Loading " + fileName);}@Overridepublic void display() {System.out.println("Displaying " + fileName);}
}
步骤3:实现虚拟代理
public class ImageProxy implements Image {private RealImage realImage;private String fileName;public ImageProxy(String fileName) {this.fileName = fileName;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(fileName);}realImage.display();}
}
步骤4:客户端使用虚拟代理
public class Client {public static void main(String[] args) {Image image = new ImageProxy("test_image.jpg");image.display(); // 只在此处加载image.display(); // 直接显示,不再加载}
}
应用场景
- 适用于需要加载大型对象的场景,例如图像、视频等。
- 在图形界面应用中,通常使用虚拟代理来延迟加载图形组件。
9.2 保护代理(Protection Proxy)
保护代理控制对真实对象的访问,主要用于权限管理。它根据客户端的身份或角色决定是否允许访问真实对象。
实现步骤
步骤1:定义主题接口
public interface Document {void view();
}
步骤2:实现真实主题
public class RealDocument implements Document {@Overridepublic void view() {System.out.println("Viewing Document");}
}
步骤3:实现保护代理
public class ProtectionProxy implements Document {private RealDocument realDocument;private String userRole;public ProtectionProxy(String userRole) {this.userRole = userRole;}@Overridepublic void view() {if (userRole.equals("Admin")) {if (realDocument == null) {realDocument = new RealDocument();}realDocument.view();} else {System.out.println("Access Denied: You do not have permission to view this document.");}}
}
步骤4:客户端使用保护代理
public class Client {public static void main(String[] args) {Document doc = new ProtectionProxy("User");doc.view(); // Access DeniedDocument adminDoc = new ProtectionProxy("Admin");adminDoc.view(); // Access Granted}
}
应用场景
- 适用于敏感数据或操作,需要根据用户权限控制访问的场景。
- 在企业级应用中常见,用于控制对重要文档或资源的访问。
9.3 缓存代理(Caching Proxy)
缓存代理在调用真实对象的方法前检查是否已经缓存了结果。如果有,则直接返回缓存结果,否则调用真实对象并将结果存入缓存。
实现步骤
步骤1:定义主题接口
public interface Data {String fetchData();
}
步骤2:实现真实主题
public class RealData implements Data {@Overridepublic String fetchData() {return "Data from Real Data Source";}
}
步骤3:实现缓存代理
import java.util.HashMap;public class CachingProxy implements Data {private RealData realData;private HashMap<String, String> cache;public CachingProxy() {this.realData = new RealData();this.cache = new HashMap<>();}@Overridepublic String fetchData() {if (cache.containsKey("data")) {System.out.println("Returning cached data.");return cache.get("data");}String data = realData.fetchData();cache.put("data", data);return data;}
}
步骤4:客户端使用缓存代理
public class Client {public static void main(String[] args) {Data dataProxy = new CachingProxy();System.out.println(dataProxy.fetchData()); // First call fetches dataSystem.out.println(dataProxy.fetchData()); // Subsequent call returns cached data}
}
应用场景
- 适用于数据查询频繁但变化不大的场景,例如Web应用中的数据库查询结果。
- 可以显著提高性能,减少对真实数据源的调用次数。
10.总结
代理模式在控制对象访问和增强系统功能方面提供了很大的灵活性,且每种变体都有其独特的用处,需要根据需求进行选择和实施。
相关文章:
【软件设计】常用设计模式--代理模式
文章目录 代理模式(Proxy Pattern)1. 概念2. 模式结构3. UML 类图4.实现方式C# 示例步骤1:定义主题接口步骤2:实现真实主题步骤3:实现代理类步骤4:客户端使用代理模式输出结果: Java 示例步骤1&…...
生命与自由,抑郁的来源
在中国文学史上,有一句极其伟大的话,它点出了所有人痛苦的根源。它出自《我与地坛》,太阳它每时每刻即是夕阳也都是旭日,当他从这一段熄灭着走下山去,收尽苍凉参照之际,也正是它在另一端燃烧着爬上山巅布散…...
CTFHUB技能树之文件上传——双写后缀
开启靶场,打开链接: 直接指明是双写绕过方法 上传06shaungxie.php,内容如下: 这一步其实最好换成.png或者.jpg或者.gif这三个符合文件格式的要求后缀 用burp抓包改包: 将php改成pphphp后再“Forward”: 上传…...
SpringBoot整合HTTPS
文章目录 1_Https 的作用2_获取证书3_配置项4_配置类5_控制类6_启动类 1_Https 的作用 保护用户的隐私信息安全: 在 HTTP 网站数据以明文方式传输,客户的隐私极容易被盗取和泄露,而部署 SSL 证书,数据以 HTTPS 加密传输…...
LVGL-从入门到熟练使用
LVGL简介 LVGL( Light and Versatile Graphics Library )是一个轻量、多功能的开源图形库。 1、丰富且强大的模块化图形组件:按钮 、图表 、列表、滑动条、图片等 2、高级的图形引擎:动画、抗锯齿、透明度、平滑滚动、图层混合等…...
【MySQL数据库】MySQL读写分离
文章目录 读写分离概念读写分离的动机读写分离的适用场景主从复制与读写分离MySQL 读写分离原理MySQL读写分离的实现方式代表性程序 MySQL读写分离实验搭建 MySQL 读写分离Amoeba 服务器配置测试读写分离 问答 读写分离 概念 读写分离是为了优化数据库性能,通过将…...
深度学习:简单计算图的反向传播传递导数计算
问题: 太郎在超市买了2个100日元一个的苹果,消费税是10%,请计算支付金额。 反向传播使用与正方向相反的箭头(粗线)表示。反向传播传递“局部导数”,将导数的值写在箭头的下方。在这个例子中,反向…...
学习AJAX请求(初步)24.10.21-10.23
1.AJAX概念 AJAX Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。 AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。 虽然所有的AJAX请求都是HTTP请求,但并非所有的HT…...
初识算法——二分查找
1.概念 二分查找算法也称折半查找,是一种非常高效的工作于有序数组的查找算法。 需求:在有序数组 A A A 内,查找值 t a r g e t target target 如果找到返回索引如果找不到返回 − 1 -1 −1 前提给定一个内含 n n n 个元素的有序数组…...
深入剖析 Java Spring 中的 @Autowired、@Resource、@Qualifier、@Inject 注解:使用详解与注意事项
文章目录 Autowired:Spring 最常用的注解1. 作用与简介2. 使用示例3. 注意事项 Resource:按名称注入的利器1. 作用与简介2. 使用示例3. 注意事项 Qualifier:解决多 bean 注入问题1. 作用与简介2. 使用示例3. 注意事项 Inject:标准…...
ThingsBoard规则链节点:Delete Attributes节点详解
引言 删除属性节点简介 用法 含义 应用场景 实际项目运用示例 智能家居安全系统 物流跟踪解决方案 工业自动化生产线 结论 引言 ThingsBoard是一个开源的物联网平台,它提供了设备管理、数据收集与处理以及实时监控等功能。其中,规则引擎是其核心…...
关于作为面试官以及如何准备面试的一些心得
关于作为面试官以及如何准备面试的一些心得 一、面试官(我站在前端角度来说) 当作为这样身份的时候,我想第一步应该是自己梳理一些从简到难、从点到面的问题 CSS - JS - 框架 - 项目 从这四个角度出发,一步一步的引导面试者的思…...
Bean对象 和 普通对象 的区别
Bean对象 和 普通对象 的区别 前言Bean的概念与new创建的对象的区别Spring Bean的优势两者使用的关键点总结 前言 在Spring框架中,我们通常将Spring容器管理的对象称为“Bean”或“Bean对象”。而通过new关键字创建的对象则被称为“对象”或“普通对象”。 Bean的…...
lego-loam featureAssociation 源码注释(二)
咱们接着往下看initializationValue();!!! FeatureAssociation():nh("~"){subLaserCloud nh.subscribe<sensor_msgs::PointCloud2>("/segmented_cloud", 1, &FeatureAssociation::laserCloudHandler, this);s…...
Claude 3.5 的六大应用场景
Claude 3.5 的六大应用场景 随着人工智能技术的飞速发展,Claude 3.5 已经成为一款强大的语言模型工具,在多个领域展现了其卓越的应用潜力。本文将通过CSDN格式,介绍Claude 3.5在六大主要领域的实际应用场景,帮助开发者和企业更好…...
进程线程知识总结
1. 程序什么时候应该使用线程,什么时候单线程效率高 使用线程:在I/O密集型或高并发的场景,例如网络服务、文件读写等。通过多线程可以同时处理多个任务,提高利用率。单线程效率高:在CPU密集型任务中,当任务…...
Rsync数据复制/备份服务应用
文章目录 1. rsync概述1.1 什么是Rsync1.2 rsync的功能1.3 rsync 的功能特性1.4 Rsync 增量复制原理1.5 生产场景架构集群备份方案 2. Rsync工作方式介绍与实践2.1 本地数据传输模式2.1.1 本地数据传输模式语法2.1.2 本地数据传输模式实践 2.2 远程Shell 数据传输模式2.2.1 远程…...
如何为自己的跨境网站添加多国语言翻译功能及推荐起尔网定制与插件开发
如何为自己的跨境网站添加多国语言翻译功能及推荐起尔网定制与插件开发 在全球化的浪潮下,跨境电商成为越来越多企业拓展国际市场的重要途径。然而,语言障碍成为了一个不可忽视的问题。为了更好地服务全球用户,为自己的跨境网站添加多国语言…...
安全见闻(3)——开阔眼界,不做井底之蛙
内容预览 ≧∀≦ゞ 安全见闻三:脚本程序与病毒声明导语脚本语言BAT/PowerShell脚本木马与宏病毒脚本病毒BIOS病毒 结语 安全见闻三:脚本程序与病毒 声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只…...
MySQL 的意向锁(Intention Locks)原理详解
1. 背景:为什么需要意向锁? MySQL 中意向锁的主要作用是用于支持行级锁与表级锁的并存,特别是在 InnoDB 存储引擎中。InnoDB 提供了行级锁,而在某些场景下,数据库系统仍需要对整张表加锁,例如 LOCK TABLES …...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
