当前位置: 首页 > news >正文

【设计模式】Java 设计模式之代理模式(Proxy Pattern)

代理模式深入分析

一、概述

代理模式是一种为其他对象提供一种代理以控制对这个对象的访问的设计模式。在某些情况下,一个对象不适合或者不能直接访问另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式的主要目的是:增强目标对象的功能;控制对目标对象的访问;实现目标对象与客户端的解耦。

二、模式结构

代理模式主要涉及三个角色:

  1. 抽象主题(Subject)角色:声明了真实主题和代理主题的共同接口,这样任何使用真实主题的地方都可以使用代理主题。
  2. 真实主题(RealSubject)角色:定义了代理所代表的真实对象,是我们最终要引用的对象。
  3. 代理主题(ProxySubject)角色:代理主题角色内部含有对真实主题的引用,从而可以操作真实主题对象,同时代理主题角色提供与真实主题相同的接口以便在任何时候都能代替真实主题。此外,代理主题角色还可以在执行真实主题操作前后添加一些操作。

三、实现方式

代理模式通常有两种实现方式:静态代理和动态代理。

  1. 静态代理
    静态代理是代理模式的最直接实现方式。代理类和被代理类实现相同的接口,代理类持有被代理类的实例,通过调用被代理类的方法来完成实际的功能。
// 抽象主题
public interface Subject {void request();
}// 真实主题
public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("Called RealSubject request()");}
}// 代理主题
public class ProxySubject implements Subject {private RealSubject realSubject;public ProxySubject() {this.realSubject = new RealSubject();}@Overridepublic void request() {// 在调用真实主题前添加一些操作System.out.println("Before calling RealSubject request()");realSubject.request();// 在调用真实主题后添加一些操作System.out.println("After calling RealSubject request()");}
}
  1. 动态代理
    动态代理利用了Java的反射机制,在运行时动态地生成代理类。这种方式比静态代理更加灵活,不需要为每个被代理类编写一个代理类。Java标准库中的java.lang.reflect.Proxy类和java.lang.invoke.MethodHandles.Lookup类是动态代理的关键。
// 抽象主题
public interface Subject {void request();
}// 真实主题
public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("Called RealSubject request()");}
}// 动态代理工厂
public class ProxyFactory {@SuppressWarnings("unchecked")public static <T> T getProxyInstance(Class<T> interfaceClass, InvocationHandler handler) {return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),new Class<?>[]{interfaceClass},handler);}
}// 调用处理器
public class MyInvocationHandler implements InvocationHandler {private Object target;public MyInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 在调用方法前添加一些操作System.out.println("Before method " + method.getName());Object result = method.invoke(target, args);// 在调用方法后添加一些操作System.out.println("After method " + method.getName());return result;}
}// 客户端代码
public class Client {public static void main(String[] args) {RealSubject realSubject = new RealSubject();InvocationHandler handler = new MyInvocationHandler(realSubject);Subject subject = ProxyFactory.getProxyInstance(Subject.class, handler);subject.request();}
}

四、优缺点分析

优点:

  1. 职责清晰:将一部分工作交给代理对象处理,真实对象可以更加专注于其核心功能的实现。
  2. 控制访问:代理模式可以对访问真实对象进行一定的限制和控制,比如权限校验、访问日志记录等。
  3. 高扩展性:可以在不修改原有代码的基础上增加新的功能。

缺点:

  1. 性能损耗:由于代理对象的存在,每次访问真实对象都需要通过代理对象,因此会有一定的性能损耗。
  2. 代码复杂度:使用代理模式会增加代码的复杂度,特别是在使用动态代理时,需要编写额外的代理工厂类和调用处理器类。

五、常见应用场景

  1. 远程代理:为一个对象在不同的地址空间提供局部代表,这样可以将网络细节隐藏起来。
  2. 虚拟代理:根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。
  3. 保护代理:控制对原始对象的访问权限。
  4. 智能引用:当调用真实对象时,代理对象进行一些附加操作,如计算真实对象的引用次数等。

六、应用案例解读

以远程代理为例,假设我们有一个远程服务,客户端需要调用这个服务上的方法。出于性能和安全考虑,我们不希望客户端直接调用远程服务,而是通过一个代理对象来进行调用。代理对象负责处理网络通信、序列化/反序列化等细节,而客户端只需与代理对象交互即可。

// 远程服务接口
public interface RemoteService {String callRemoteMethod(String arg);
}// 远程服务实现(位于远程服务器上)
public class RemoteServiceImpl implements RemoteService {@Overridepublic String callRemoteMethod(String arg) {// 执行一些远程服务上的操作return "Result from remote service: " + arg;}
}// 远程服务代理
public class RemoteServiceProxy implements RemoteService {private String serverAddress;public RemoteServiceProxy(String serverAddress) {this.serverAddress = serverAddress;}@Overridepublic String callRemoteMethod(String arg) {// 处理网络通信,发送请求到远程服务器// 接收响应,并返回结果// 这里的实现会依赖于具体的网络通信库或框架String result = sendRequestToServer(serverAddress, arg);return result;}private String sendRequestToServer(String serverAddress, String arg) {// 简化示例,实际实现会涉及网络通信和序列化/反序列化return "Proxy result for server at " + serverAddress + ": " + arg;}
}// 客户端代码
public class Client {public static void main(String[] args) {RemoteService proxy = new RemoteServiceProxy("remote.server.address");String result = proxy.callRemoteMethod("Hello, remote service!");System.out.println(result);}
}

在这个案例中,RemoteServiceProxy作为远程服务的代理,负责处理与远程服务器的通信。客户端代码通过调用代理对象的callRemoteMethod方法,间接地调用远程服务上的方法。代理对象隐藏了网络通信的复杂性,使客户端代码更加简洁和易于管理。

总结来说,代理模式是一种强大的设计模式,它可以在不修改原有代码的基础上增强对象的功能、控制对象的访问以及实现解耦。通过合理地应用代理模式,我们可以构建出更加灵活、可扩展和易于维护的软件系统。
七、代理模式的变种

代理模式有多种变种,每一种都有其特定的用途和适用场景。

  1. 保护代理(Protection Proxy):控制对原始对象的访问权限。这种代理模式常用于实现访问控制,比如限制对某个方法的访问,或者检查用户权限等。

  2. 虚拟代理(Virtual Proxy):主要用于控制对开销大的对象的访问。当实际对象在创建或初始化时开销很大时,虚拟代理可以延迟对象的创建,直到真正需要时才创建。

  3. 智能引用代理(Smart Reference Proxy):当调用真实对象时,代理对象进行一些附加操作,比如引用计数、日志记录、事务处理等。

  4. 缓存代理(Caching Proxy):为开销大的运算结果提供暂时的存储,在下次运算时,如果输入相同则直接返回缓存的结果。

  5. 同步代理(Synchronization Proxy):为多个线程共享的资源提供安全访问。

八、与其他设计模式的关联

代理模式经常与其他设计模式结合使用,以实现更复杂的系统结构和功能。

  1. 与装饰器模式(Decorator Pattern):装饰器模式用于动态地给一个对象添加一些额外的职责。在某种意义上,代理模式也可以看作是一种特殊的装饰器模式,它主要关注于控制对对象的访问和增强对象的功能,而不是动态地添加职责。

  2. 与适配器模式(Adapter Pattern):适配器模式用于将一个类的接口转换成客户端所期望的另一种接口。在某些情况下,代理模式可以用来实现适配器模式,特别是当需要转换的接口涉及访问控制或延迟加载时。

九、最佳实践

  1. 明确代理的目的:在使用代理模式之前,首先要明确代理的目的,是为了增强功能、控制访问还是其他目的。

  2. 考虑性能开销:代理模式会增加一定的性能开销,因为每次访问原始对象都需要通过代理对象。因此,在性能敏感的场景中,需要仔细权衡是否使用代理模式。

  3. 保持接口一致性:代理对象应该尽量保持与原始对象相同的接口,这样客户端代码才能无缝地切换到代理对象。

  4. 谨慎使用动态代理:动态代理虽然提供了很大的灵活性,但也会增加代码的复杂性和维护成本。因此,在不需要动态代理的情况下,应尽量使用静态代理。

十、代理模式在实际项目中的应用

代理模式在实际项目中有着广泛的应用,特别是在需要增强对象功能、控制访问权限或实现延迟加载等场景中。以下是一些具体的应用示例:

  1. 数据库访问代理:在数据库访问层,我们通常会使用代理模式来封装数据库操作,实现连接池管理、事务控制、SQL日志记录等功能。代理对象负责处理与数据库的通信细节,而业务代码只需与代理对象交互,无需关心底层数据库的具体实现。

  2. 远程服务调用代理:在分布式系统中,服务之间的调用通常通过代理对象来实现。代理对象负责处理网络通信、序列化/反序列化、负载均衡等细节,使得服务调用更加简单和可靠。

  3. 文件访问代理:在文件系统中,我们可以使用代理模式来封装文件读写操作,实现文件加密、压缩、缓存等功能。代理对象负责处理文件的读写细节,而应用程序只需通过代理对象来访问文件。

  4. API网关:在微服务架构中,API网关通常作为服务调用的代理,负责处理认证、授权、限流、熔断等逻辑。API网关作为代理对象,将客户端的请求转发到相应的微服务,并处理响应结果。

  5. UI组件代理:在图形用户界面(GUI)开发中,代理模式可以用于封装复杂的UI组件,实现组件的延迟加载、动态替换或增强功能。代理对象可以管理组件的生命周期,并提供统一的接口供应用程序使用。

十一、代理模式的扩展与思考

代理模式作为一种经典的设计模式,在实际应用中有着广泛的应用场景。然而,随着技术的不断发展和业务需求的不断变化,我们也需要对代理模式进行扩展和思考。

  1. 异步代理:在处理耗时操作时,我们可以考虑使用异步代理来避免阻塞主线程。异步代理可以将操作放到后台线程中执行,并通过回调函数或Future对象等方式将结果返回给调用方。

  2. 动态代理与AOP(面向切面编程):动态代理是实现AOP的关键技术之一。通过动态代理,我们可以在不修改原有代码的情况下,为对象添加额外的行为(如日志记录、性能监控等)。这使得AOP成为一种强大的编程范式,能够极大地提高代码的可维护性和可扩展性。

  3. 代理模式的性能优化:虽然代理模式带来了很多好处,但也会引入一定的性能开销。因此,在实际应用中,我们需要对代理模式进行性能优化。例如,我们可以通过缓存代理对象、减少代理链的长度、优化网络通信等方式来降低性能开销。

  4. 代理模式与其他技术的结合:随着技术的发展,出现了很多新的编程范式和技术,如函数式编程、响应式编程等。我们可以思考如何将代理模式与这些新技术结合,以更好地满足业务需求和提高代码质量。

十二、总结与展望

代理模式作为一种经典的设计模式,在软件开发中发挥着重要的作用。通过合理地应用代理模式,我们可以实现对象的增强、访问控制、延迟加载等功能,提高代码的可维护性和可扩展性。然而,随着技术的不断发展和业务需求的不断变化,我们也需要对代理模式进行扩展和思考,以适应新的挑战和需求。未来,我们可以继续探索代理模式与其他技术的结合,以及如何更好地优化代理模式的性能,为构建高质量的软件系统提供有力支持。

相关文章:

【设计模式】Java 设计模式之代理模式(Proxy Pattern)

代理模式深入分析 一、概述 代理模式是一种为其他对象提供一种代理以控制对这个对象的访问的设计模式。在某些情况下&#xff0c;一个对象不适合或者不能直接访问另一个对象&#xff0c;而代理对象可以在客户端和目标对象之间起到中介的作用。 代理模式的主要目的是&#xf…...

逻辑数据平台的 NoETL 之道(内含QA)

作者简介&#xff1a; 余俊&#xff0c;Aloudata 合伙人 & 技术副总裁。拥有 18 年互联网技术和大数据平台相关架构经验。作为主架构师及核心研发主导并完成了 Alibaba B2B 首个海量分布式 KV 存储系统&#xff0c;作为网站架构师负责 Aliexpress 全球买全球卖交易系统的第…...

低代码与数智制造:引领软件开发的革新之旅

在当今快速发展的数字化时代&#xff0c;软件开发已经渗透到各行各业&#xff0c;成为推动社会进步的重要力量。随着技术的不断进步&#xff0c;低代码开发与数智制造正逐渐崭露头角&#xff0c;成为引领软件开发领域革新的两大关键要素。本文将深入探讨低代码与数智制造的内涵…...

安装 AWS Load Balancer Controller 附加组件

1 创建一个 IAM policy #curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.4/docs/install/iam_policy.json#aws iam create-policy \--policy-name AWSLoadBalancerControllerIAMPolicy \--policy-document file://iam_policy.…...

性能测试什么时候开始?性能测试流程介绍

性能测试什么时候开始? 一般在系统功能稳定没有大的缺陷之后开始执行。但前期准备工作可以从系统需求分析时就开始&#xff1a;性能目标制定、场景获取、环境申请等。 一、制定性能测试目标 在特定的并发用户数下测试特定场景的响应时间 在一定的响应时间的要求下来测试特…...

爬虫逆向实战(36)-某建设监管平台(RSA,魔改)

一、数据接口分析 主页地址&#xff1a;某建设监管平台 1、抓包 通过抓包可以发现网站首先是请求了一个/prod-api/mohurd-pub/vcode/genVcode的接口&#xff0c;用于获取滑块验证码的图片 滑块验证之后&#xff0c;请求了/prod-api/mohurd-pub/dataServ/findBaseEntDpPage这…...

DeepLearning in Pytorch|共享单车预测NN详解(思路+代码剖析)

目录 概要 一、代码概览 二、详解 基本逻辑 1.数据准备 2.设计神经网络 初版 改进版 测试 总结 概要 原文链接&#xff1a;DeepLearning in Pytorch|我的第一个NN-共享单车预测 我的第一个深度学习神经网络模型---利用Pytorch设计人工神经网络对某地区租赁单车的使用…...

如何配置Apache的反向代理

目录 前言 一、反向代理的工作原理 二、Apache反向代理的配置 1. 安装Apache和相关模块 2. 配置反向代理规则 3. 重启Apache服务器 三、常见的使用案例 1. 负载均衡 2. 缓存 3. SSL加密 总结 前言 随着Web应用程序的不断发展和扩展&#xff0c;需要处理大量的请求和…...

Vue.js 应用实现监控可观测性最佳实践

前言 Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简单还是复杂的界面&#xff0c;Vue 都可以胜任。 TinyPro 是一套使用 Vue …...

Rust 语言中符号 :: 的使用场景

在 Rust 语言中&#xff0c;:: 符号主要用于以下几个场合&#xff1a; 指定关联函数或关联类型&#xff1a; 关联函数&#xff08;也称为静态方法&#xff09;是与类型关联而非实例关联的函数。它们使用 :: 符号来调用。例如&#xff1a; let value String::from("Hello,…...

Java 获取笔记本WiFi网络基站信息的方法

在Android开发中&#xff0c;获取基站信息&#xff08;如基站ID、运营商信息、信号强度等&#xff09;通常涉及使用TelephonyManager类。请注意&#xff0c;由于隐私和安全的考虑&#xff0c;从Android 10&#xff08;API级别29&#xff09;开始&#xff0c;对访问此类信息的权…...

Python如何处理拥塞控制

拥塞控制是计算机网络中用于防止网络拥塞&#xff08;即过多的数据导致网络性能下降&#xff09;的一系列技术和算法。在Python中&#xff0c;处理拥塞控制通常不直接涉及到代码层面的实现&#xff0c;因为拥塞控制主要是在网络协议栈&#xff08;如TCP/IP&#xff09;和操作系…...

【ArcGIS】栅格数据进行标准化(归一化)处理

栅格数据进行标准化&#xff08;归一化&#xff09;处理 方法1&#xff1a;栅格计算器方法2&#xff1a;模糊分析参考 栅格数据进行标准化(归一化)处理 方法1&#xff1a;栅格计算器 栅格计算器&#xff08;Raster Calculator&#xff09; 计算完毕后&#xff0c;得到归一化…...

【CMake】顶层 CMakeList.txt 常用命令总结

文章目录 cmake_minimum_required简介使用案例普通设置执行构建的cmake版本低于<min> project简介使用案例普通设置 set简介使用案例普通设置 cmake_minimum_required 简介 功能&#xff1a;为项目设置cmake的最低要求版本常用程度&#xff1a;⭐⭐⭐⭐⭐命令格式 cma…...

mac启动elasticsearch

1.首先下载软件&#xff0c;然后双击解压&#xff0c;我用的是7.17.3的版本 2.然后执行如下命令 Last login: Thu Mar 14 23:14:44 on ttys001 diannao1xiejiandeMacBook-Air ~ % cd /Users/xiejian/local/software/elasticsearch/elasticsearch-7.17.3 diannao1xiejiandeMac…...

【FFmpeg】ffmpeg 命令行参数 ⑤ ( 使用 ffmpeg 命令提取 音视频 数据 | 保留封装格式 | 保留编码格式 | 重新编码 )

文章目录 一、使用 ffmpeg 命令提取 音视频 数据1、提取音频数据 - 保留封装格式2、提取视频数据 - 保留封装格式3、提取视频数据 - 保留编码格式4、提取视频数据 - 重新编码5、提取音频数据 - 保留编码格式6、提取音频数据 - 重新编码 一、使用 ffmpeg 命令提取 音视频 数据 1…...

JMeter 二次开发之环境准备

通过JMeter二次开发&#xff0c;可以充分发挥JMeter的潜力&#xff0c;定制化和扩展工具的能力以满足具体需求。无论是开发自定义插件、函数二次开发还是定制UI&#xff0c;深入学习和掌握JMeter的二次开发技术&#xff0c;将为接口功能测试/接口性能测试工作带来更多的便利和效…...

Laravel Class ‘Facade\Ignition\IgnitionServiceProvider‘ not found 解决

Laravel Class Facade\Ignition\IgnitionServiceProvider not found 问题解决 问题 在使用laravel 更新本地依赖环境时&#xff0c;出现报错&#xff0c;如下&#xff1a; 解决 这时候需要更新本地的composer&#xff0c;然后在更新本地依赖环境。 命令如下&#xff1a; co…...

DNS 技巧与窍门

简介 在本文中&#xff0c;您将学习三种可以使用 DNS 完成的技巧。如果您曾经进行过任何与 DNS 配置相关的工作&#xff0c;这些小技巧可能会帮助您更快地完成工作流程。您将学习一些在终端中使用的命令和处理 DNS 数据的方法&#xff0c;比如如何检查当前的域名服务器。完成后…...

第2章 信息技术基础

本章学习要点 全面了解医院信息系统建设所涉及的主要信息技术以及这些技术的应用情况。 计算机与网络、信息技术与信息系统、数字媒体与数据存储技术、条形码(二维码)、RFID技术、云计算、APP技术 1.XML 可扩展标记语言与Access&#xff0c;Oracle和SQL Server等数据库不同…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...