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

设计模式 结构型 代理模式(Proxy Pattern)与 常见技术框架应用 解析

在这里插入图片描述

代理模式(Proxy Pattern)是一种常见的设计模式,在软件开发中有着广泛的应用。其核心思想是通过创建一个代理类来控制对另一个对象的访问,从而实现对目标对象功能的扩展、保护或其他附加操作。

一、核心思想

代理模式的核心思想在于提供一个代理对象,作为客户端与目标对象之间的中介。客户端并不直接调用目标对象的方法,而是通过调用代理对象的方法来间接调用目标对象的方法。这样可以在调用目标对象方法之前或之后添加额外的逻辑,如权限检查、日志记录、事务处理等。

二、定义与结构

定义:代理模式为其他对象提供一种代理以控制对这个对象的访问。

结构

  • 抽象角色(Subject):通过接口或抽象类声明真实角色实现的业务方法。
  • 代理角色(Proxy):实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
  • 真实角色(Real Subject):实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

角色

在代理模式中,通常涉及以下三个角色:

  • 抽象主题(Subject):定义了真实主题和代理主题的共同接口。
  • 真实主题(Real Subject):实现了具体的业务逻辑,是代理模式中被代理的对象。
  • 代理主题(Proxy Subject):持有对真实主题的引用,可以在调用真实主题之前或之后执行附加的操作。

三、实现步骤及代码示例

以下是通过Java技术框架实现代理模式的详细步骤及代码示例:

静态代理

  1. 定义抽象主题接口:
public interface Subject {void request();
}
  1. 实现真实主题类:
public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}
  1. 实现代理主题类:
public class ProxySubject implements Subject {private RealSubject realSubject;@Overridepublic void request() {if (realSubject == null) {realSubject = new RealSubject();}preRequest();realSubject.request();postRequest();}private void preRequest() {System.out.println("ProxySubject: Preparing for request.");}private void postRequest() {System.out.println("ProxySubject: Finishing up request.");}
}
  1. 客户端代码:
public class Client {public static void main(String[] args) {Subject subject = new ProxySubject();subject.request();}
}

动态代理

  1. 定义抽象主题接口(同上)。
  2. 实现真实主题类(同上)。
  3. 创建InvocationHandler实现类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class ProxyHandler implements InvocationHandler {private final Object target;public ProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {preRequest();Object result = method.invoke(target, args);postRequest();return result;}private void preRequest() {System.out.println("ProxySubject: Preparing for request.");}private void postRequest() {System.out.println("ProxySubject: Finishing up request.");}
}
  1. 客户端代码:
import java.lang.reflect.Proxy;public class Client {public static void main(String[] args) {RealSubject realSubject = new RealSubject();InvocationHandler handler = new ProxyHandler(realSubject);Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),realSubject.getClass().getInterfaces(),handler);subject.request();}
}

四、常见技术框架应用

1、网络请求代理服务器

在网络请求中,可能会使用代理服务器。假设我们有一个简单的网络请求接口和实现:

  • 定义抽象主题(网络请求接口):
interface NetworkRequest {String request(String url);
}
  • 真实主题(实际的网络请求实现):
class RealNetworkRequest implements NetworkRequest {@Overridepublic String request(String url) {System.out.println("Sending request to " + url);// 这里可以是实际的网络请求代码,比如使用HttpURLConnection等return "Response from " + url;}
}
  • 代理(带有缓存功能的网络请求代理):
import java.util.HashMap;
import java.util.Map;class CachedNetworkRequestProxy implements NetworkRequest {private RealNetworkRequest realRequest;private Map<String, String> cache = new HashMap<>();@Overridepublic String request(String url) {if (cache.containsKey(url)) {System.out.println("Retrieving from cache for " + url);return cache.get(url);} else {if (realRequest == null) {realRequest = new RealNetworkRequest();}String response = realRequest.request(url);cache.put(url, response);return response;}}
}
  • 使用示例:
NetworkRequest request = new CachedNetworkRequestProxy();
System.out.println(request.request("https://example.com"));
System.out.println(request.request("https://example.com"));

这里代理对象CachedNetworkRequestProxy在第一次请求时会调用真实对象RealNetworkRequest进行网络请求,然后将结果缓存起来。之后相同的请求就直接从缓存中获取,减少了网络请求的次数。

2、Spring AOP

在Java中,代理模式也很常见,特别是在Spring框架中。以下是一个简单的Spring AOP(面向切面编程)示例:

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;// Service interface
public interface SimpleService {void perform();
}// Service implementation
public class SimpleServiceImpl implements SimpleService {@Overridepublic void perform() {System.out.println("Performing service operation");}
}// Before advice
public class LoggingBeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("Logging before method: " + method.getName());}
}// Client code
public class ProxyDemo {public static void main(String[] args) {SimpleService service = new SimpleServiceImpl();ProxyFactory factory = new ProxyFactory();factory.setTarget(service);factory.addAdvice(new LoggingBeforeAdvice());SimpleService proxy = (SimpleService) factory.getProxy();proxy.perform(); // Output: Logging before method: perform \n Performing service operation}
}

在这个例子中,ProxyFactory创建了一个代理对象,并在方法调用之前添加了日志记录功能。

在Java中,代理模式通常用于远程方法调用(RMI)、JDK动态代理或CGLIB代理。在.NET中,可以用Castle DynamicProxy库来创建代理。而在Python中,wrapt库提供了强大的装饰器和代理功能。在C#中,可以使用RealProxy类来实现动态代理。这些技术框架中的代理模式实现方式虽然有所不同,但核心思想都是相同的,即通过代理对象来控制对目标对象的访问。

五、应用场景

代理模式的应用场景非常广泛,包括但不限于以下几个方面:

  1. 远程代理:为其他对象提供一种代理以控制对这个对象的远程访问。例如,在分布式系统中,客户端可以通过代理对象来访问远程服务器上的对象。
  2. 虚拟代理:根据需要创建开销很大的对象。在真实对象创建之前,虚拟代理对象可以充当其代理。例如,在加载大型图片或视频时,可以先显示一个占位符或缩略图,待图片或视频加载完成后再显示真实内容。
  3. 安全代理:控制对资源的访问权限。例如,在Web应用中,可以通过代理对象来检查用户是否具有访问某个资源的权限。
  4. 智能代理:当调用真实对象时,代理对象可以附加一些额外的处理逻辑。例如,在调用数据库查询方法之前,代理对象可以自动添加分页、排序等处理逻辑。

六、优缺点

优点

  1. 中介作用:代理对象可以在客户端和目标对象之间起到中介的作用,从而保护目标对象。
  2. 功能扩展:代理对象可以扩展目标对象的功能,而不需要修改目标对象的代码。
  3. 降低耦合度:代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性。

缺点

  1. 类数量增加:代理模式会造成系统设计中类的数量增加,从而增加了系统的复杂度。
  2. 请求处理变慢:在客户端和目标对象之间增加一个代理对象,可能会造成请求处理速度变慢。

综上所述,代理模式是一种非常有用的设计模式,它可以在不修改目标对象代码的前提下,实现对目标对象功能的扩展和保护。同时,代理模式也具有一定的缺点,需要在具体应用场景中进行权衡和选择。

在这里插入图片描述

相关文章:

设计模式 结构型 代理模式(Proxy Pattern)与 常见技术框架应用 解析

代理模式&#xff08;Proxy Pattern&#xff09;是一种常见的设计模式&#xff0c;在软件开发中有着广泛的应用。其核心思想是通过创建一个代理类来控制对另一个对象的访问&#xff0c;从而实现对目标对象功能的扩展、保护或其他附加操作。 一、核心思想 代理模式的核心思想在…...

Linux环境(CentOs7) 安装 Node环境

Linux环境&#xff08;CentOs7&#xff09; 安装 Node环境 使用NodeSource安装Node.js 1、清除缓存&#xff08;可选但推荐&#xff09; sudo yum clean all2、添加NodeSource仓库&#xff0c;根据你想要安装的Node.js版本&#xff0c;选择相应的NodeSource安装脚本。例如&am…...

Tailwind CSS 实战:现代登录注册页面开发

在前端开发中&#xff0c;登录注册页面是最常见的需求之一。一个设计精美、交互友好的登录注册页面不仅能提升用户体验&#xff0c;还能增加产品的专业度。本文将详细介绍如何使用 Tailwind CSS 开发一个现代化的登录注册页面。 设计思路 在开始编码之前&#xff0c;我们先明…...

Unity2022接入Google广告与支付SDK、导出工程到Android Studio使用JDK17进行打包完整流程与过程中的相关错误及处理经验总结

注&#xff1a;因为本人也是第一次接入广告与支付SDK相关的操作&#xff0c;网上也查了很多教程&#xff0c;很多也都是只言片语或者缺少一些关键步骤的说明&#xff0c;导致本人也是花了很多时间与精力踩了很多的坑才搞定&#xff0c;发出来也是希望能帮助到其他人在遇到相似问…...

反向传播算法的偏置更新步骤

偏置的更新步骤 假设我们有一个三层神经网络&#xff08;输入层、隐藏层和输出层&#xff09;&#xff0c;并且每层的激活函数为 sigmoid 函数。我们需要更新隐藏层和输出层的偏置。以下是详细的步骤&#xff1a; 1. 计算误差项&#xff08;Error Term&#xff09; 输出层的…...

条款47:请使用 traits classes 表现类型信息(Use traits classes for information about types)

条款47&#xff1a;请使用 traits classes 表现类型信息 1.1 提出问题 想一想&#xff0c;下面的功能如何实现&#xff1f;&#xff08;可以查看std::advance源码&#xff09; template<typename IterT, typename DistT> void advance(IterT& iter, DistT d); /…...

yolov5和yolov8的区别

1. yolov5有建议框&#xff0c;yolov8没有建议框 2. yolov5标签中有自信度&#xff0c;而yolov8没有自信度。因为自信度是建议框和真实框的交集 3. yolov5有三个损失函数&#xff0c;回归问题&#xff1a;预测框和建议框的损失(中心点宽高偏移量的损失)&#xff1a;CIOUFocal…...

Redis 实现分布式锁

文章目录 引言一、Redis的两种原子操作1.1 Redis 的原子性1.2 单命令1.3 Lua 脚本1.4 对比单命令与 Lua 脚本 二、Redis 实现分布式锁2.1 分布式锁的概念与需求2.1.1 什么是分布式锁&#xff1f;2.1.2 分布式锁的常见应用场景 2.2 基于 Redis 的分布式锁实现2.2.1 锁的获取与释…...

django StreamingHttpResponse fetchEventSource实现前后端流试返回数据并接收数据的完整详细过程

django后端环境介绍&#xff1a; Python 3.10.14 pip install django-cors-headers4.4.0 Django5.0.6 django-cors-headers4.4.0 djangorestframework3.15.2 -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple 总环境如下&#xff1a; Package Version -…...

SpringSpringBoot常用注解总结

目录 1. SpringBootApplication 2. Spring Bean 相关 2.1. Autowired 2.2. Component,Repository,Service, Controller 2.3. RestController 2.4. Scope 2.5. Configuration 3. 处理常见的 HTTP 请求类型 3.1. GET 请求 3.2. POST 请求 3.3. PUT 请求 3.4. DELETE 请…...

24.小R的随机播放顺序<字节青训营-中等题>

1.题目 问题描述 小R有一个特殊的随机播放规则。他首先播放歌单中的第一首歌&#xff0c;播放后将其从歌单中移除。如果歌单中还有歌曲&#xff0c;则会将当前第一首歌移到最后一首。这个过程会一直重复&#xff0c;直到歌单中没有任何歌曲。 例如&#xff0c;给定歌单 [5, …...

【QT】增删改查 XML 文件的类

使用单例类模板实现的对XML文件的节点、属性、文本进行增删改查,可以直接用! 直接POST代码,比较简单好用。 针对以下格式的xml文件比较适用 每个节点的名称都不一样,节点包含了各种属性。 <?xml version="1.0" encoding="UTF-8"?> <config…...

Linux-掉电保护方案

参考链接 https://blog.csdn.net/pwl999/article/details/109411919硬件设计 设备树 驱动程序 #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/gpio.h>int irq;//中断服务函数 irqreturn_t tes…...

php获取字符串中的汉字

在PHP中&#xff0c;可以使用正则表达式来提取字符串中的汉字。汉字通常位于Unicode范围\u4e00-\u9fa5之内&#xff0c;因此可以使用preg_match_all函数配合适当的正则表达式来实现。 以下是一个PHP代码示例&#xff0c;它会从给定的字符串中提取出所有的汉字&#xff1a; fu…...

java: JDK isn‘t specified for module ‘product-service‘问题解决

目录 问题 解决方法 1.打开File->Project Structure... 2.将Project SDK修改为17 Oracle OpenJDK 17.0.12&#xff0c;并Apply&#xff0c;OK 问题 添加module后报错&#xff1a;java: JDK isnt specified for module product-service 查看pom.xml文件也添加了对应的JDK…...

使用工厂+策略模式实现去除繁琐的if else

使用工厂策略模式实现去除繁琐的if else 在中间有一个mapstruct的bug&#xff0c;即在修改实体类中的类型时&#xff0c;或者修改属性名字&#xff0c;mapstruct都无法进行转换&#xff0c;会报错&#xff0c;此时需要maven cleanmaven compile即可 前言 在这次的开发中&#…...

Dubbo3入门项目搭建

开发环境&#xff1a;jdk8、dubbo3.2.9、nacos2.3.0、springboot2.7.17、dubbo-admin0.6.0。 Dubbo 是一个高性能的 Java RPC&#xff08;远程调用&#xff09;框架&#xff0c;最初由阿里巴巴开发并开源&#xff0c;主要用于构建 SOA 架构下的分布式应用系统( soa简单理解就是…...

形象地理解UE4中的数据结构 TLinkedListBase

大家都熟知链表&#xff0c;但不一定能快速看懂UE4中的数据结构。 TLinkedListBase表示“链接”中的一个结点&#xff0c;有三个成员&#xff1a; 一、ElementType Element; 表示具体的业务&#xff0c;例如int链条中的一个整数。 二、NextLink 表示 “下一个Node”&#…...

Python自然语言处理利器:SnowNLP模块深度解析、安装指南与实战案例

Python自然语言处理之SnowNLP模块介绍、安装与常见操作案例 一、SnowNLP模块介绍 SnowNLP是一个专为中文文本设计的Python库&#xff0c;它基于自然语言处理技术&#xff0c;提供了多种功能&#xff0c;包括分词、词性标注、情感分析、文本转换&#xff08;简繁转换&#xff…...

Llama系列关键知识总结

系列文章目录 第一章&#xff1a;LoRA微调系列笔记 第二章&#xff1a;Llama系列关键知识总结 第三章&#xff1a;LLaVA模型讲解与总结 文章目录 系列文章目录Llama: Open and Efficient Foundation Language Models关键要点LLaMa模型架构&#xff1a;Llama2分组查询注意力 (G…...

别再写低效循环了:深入理解Qt隐式共享与C++17的std::as_const

别再写低效循环了&#xff1a;深入理解Qt隐式共享与C17的std::as_const 在代码审查中&#xff0c;你是否经常看到这样的写法&#xff1f; const QStringList& list oldList; for (auto& str : list) {// 处理字符串 }这种看似"规范"的写法&#xff0c;实际上…...

新手福音:用快马AI生成带详解注释的Arduino交通灯实验代码

作为一个刚接触单片机的新手&#xff0c;第一次看到Arduino开发板时既兴奋又迷茫。那些闪烁的LED灯和蜂鸣器背后到底藏着什么秘密&#xff1f;今天我就用InsCode(快马)平台来探索一个有趣的交通灯模拟项目&#xff0c;整个过程比想象中简单多了。 项目构思 我想做一个能模拟真实…...

告别双流!用Vision Transformer (ViT) 搭建单流目标跟踪器OSTrack,实测速度提升40%

单流目标跟踪新范式&#xff1a;ViT驱动的OSTrack实战解析 在计算机视觉领域&#xff0c;目标跟踪技术正经历着从传统双流架构向单流范式的革命性转变。当我们面对复杂场景中的实时跟踪需求时&#xff0c;传统方法的性能瓶颈日益凸显——特征提取与关系建模的割裂处理导致计算冗…...

小米智能家居与Home Assistant深度整合方案

小米智能家居与Home Assistant深度整合方案 【免费下载链接】ha_xiaomi_home Xiaomi Home Integration for Home Assistant 项目地址: https://gitcode.com/GitHub_Trending/ha/ha_xiaomi_home 小米智能家居与Home Assistant的深度整合为用户提供了全面的智能设备控制解…...

S2-Pro自动化运维脚本生成:应对Linux服务器常见管理任务

S2-Pro自动化运维脚本生成&#xff1a;应对Linux服务器常见管理任务 1. 运维工程师的新助手 最近遇到个挺有意思的事。我们团队新来的运维小哥&#xff0c;处理服务器问题时总要先翻半天文档&#xff0c;再到处搜脚本模板。看着他手忙脚乱的样子&#xff0c;我突然想起自己刚…...

Java Web新手必看:EDUCODER头哥MVC用户登录实战(含JDBC连接避坑指南)

Java Web新手实战&#xff1a;EDUCODER平台MVC用户登录全流程解析 第一次接触Java Web开发时&#xff0c;最让人兴奋的莫过于亲手实现一个完整的用户登录系统。这不仅是对MVC架构的直观理解&#xff0c;更是打通前后端数据流的关键里程碑。在EDUCODER这样的实训平台上&#xff…...

单片机抢答器项目避坑指南:从按键抖动处理到中断优先级设置

单片机抢答器项目避坑指南&#xff1a;从按键抖动处理到中断优先级设置 在嵌入式系统开发中&#xff0c;抢答器是一个经典的教学项目&#xff0c;但看似简单的功能背后却隐藏着许多技术细节。很多开发者在实现基本功能后&#xff0c;往往会忽略一些关键优化点&#xff0c;导致系…...

Vita3K模拟器终极指南:免费跨平台畅玩PSVita游戏

Vita3K模拟器终极指南&#xff1a;免费跨平台畅玩PSVita游戏 【免费下载链接】Vita3K Experimental PlayStation Vita emulator 项目地址: https://gitcode.com/gh_mirrors/vi/Vita3K 想要在电脑上重温《女神异闻录4黄金版》的经典剧情&#xff0c;或是体验《A Rose in …...

QGIS进阶指南:动态标注与条件表达式高级应用

1. 动态标注的核心价值与应用场景 当你面对一个包含上千条建筑数据的地图图层时&#xff0c;传统静态标注会显得力不从心——商场和医院用相同字体显示&#xff0c;重要地标淹没在普通建筑中&#xff0c;数据更新后还得手动调整样式。这就是动态标注技术大显身手的时候了。 动态…...

用Verilog手搓一个IEEE754浮点加法器:从状态机设计到FPGA上板验证(附完整代码)

从零构建IEEE754浮点加法器&#xff1a;Verilog状态机设计与FPGA实战全解析 1. 浮点运算器的工程实现挑战 在数字信号处理和高性能计算领域&#xff0c;浮点运算器一直是核心组件。与整数运算不同&#xff0c;浮点数的特殊存储格式使得其运算过程复杂得多。IEEE754标准定义了浮…...