【设计模式】之代理模式(两种)
系列文章目录
(其他设计模式可以参考 👉👉👉)设计模式_小杰不秃头的博客 😊😄😛
前言
今天继续给大家介绍23种设计模式中的代理模式,熟悉Spring的小伙伴都知道,Aop使用的就是代理模式,所以,代理模式还是非常重要的,在工作中用的也是非常的多。🌈
一、代理模式
代理模式(Proxy Pattern)是面向对象编程中的一种设计模式,它为其他对象提供一个代理或占位符,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用,客户端并不直接与目标对象交互,而是通过代理对象来间接调用目标对象的方法。(简单理解就是“房子中介”的一个角色)
特点
- 中介作用:代理对象作为客户端和目标对象之间的中介,可以拦截或修改客户端对目标对象的请求。
- 功能增强:可以在不修改目标对象代码的前提下,通过代理对象为目标对象增加额外的功能。如:Spring中的AOP
- 控制访问:代理对象可以控制对目标对象的访问,比如检查权限、记录日志、实现延迟加载等。
举一个简单的例子帮助大家理解,假如说你想买一个房子,但是你没有时间去挑选,所以你就找了一个房子中介帮你去找房子,这个过程就是一个代理的过程,房子中介就是一个代理对象。
二、静态代理
1、静态代理定义和特点
静态代理(Static Proxy):是在程序编译时确定代理类的代码,代理类和目标类实现了相同的接口。静态代理的实现相对简单,代理对象和目标对象实现相同的接口,客户端通过代理对象调用目标对象的方法。
特点:静态代理需要手动编写代理类的代码,因此当接口发生变化时,代理类也需要相应地修改。由于代理类在编译期间就已经确定,因此性能相对较高。但是,静态代理只能为给定接口的实现类做代理,如果接口不同则需要重新定义不同的代理类。
2、使用场景
使用场景:静态代理通常用于为一些功能较为简单的类提供代理,如增加日志记录、性能监控等功能。由于静态代理需要手动编写代理类的代码,因此它通常适用于接口稳定、功能较为简单的场景。
3、静态代理的简单实现
这里举一个比较粗糙的例子,模拟插入订单的这个业务场景。
跟我们平时开发的一样,首先创建实体类Order
public class Order {private String info;private String userId;public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}@Overridepublic String toString() {return "Order{" +"info='" + info + '\'' +", userId='" + userId + '\'' +'}';}
}
创建持久层的接口和实现类
public interface OrderDao {int insertOrder(Order order);
}public class OrderDaoImpl implements OrderDao {@Overridepublic int insertOrder(Order order) {System.out.println("持久层...插入订单..."+order.toString());return 1;}
}
创建服务层的接口和实现类
public interface OrderService {int insertOrder(Order order);
}public class OrderServiceImpl implements OrderService {private OrderDao orderDao;@Overridepublic int insertOrder(Order order) {orderDao = new OrderDaoImpl();System.out.println("业务层...调用持久层insertOrder方法...");return orderDao.insertOrder(order);}
}
关键一步,创建静态代理对象
public class OrderServiceImplStaticProxy {private OrderService orderService;public int insertOrder(Order order){before();orderService = new OrderServiceImpl();int result = orderService.insertOrder(order);after();return result;}private void after() {System.out.println("静态代理对象...提交事务...");}private void before() {System.out.println("静态代理对象...开启事务...");}
}
测试
public class Test {public static void main(String[] args) {Order order = new Order();order.setInfo("xxxx笔记本电脑");order.setUserId("1");OrderServiceImplStaticProxy proxy = new OrderServiceImplStaticProxy();proxy.insertOrder(order);}
}/*打印结果:
静态代理对象...开启事务...
业务层...调用持久层insertOrder方法...
持久层...插入订单...Order{info='xxxx笔记本电脑', userId='1'}
静态代理对象...提交事务...
*/
三、动态代理
1、动态代理定义和特点
动态代理(Dynamic Proxy)是在程序运行过程中通过反射机制动态生成代理类的代码,实现对目标类的代理访问。动态代理可以代理任意实现了接口的类,不受接口的限制。
特点:动态代理可以根据具体需求动态生成代理类,避免了手动编写代理类的繁琐工作,方便接口的扩展和修改。由于动态代理在程序运行时生成代理类的代码,因此性能较静态代理略低。但是,动态代理的灵活性 更高,可以代理任意实现了接口的类。
2、使用场景
使用场景:动态代理广泛应用于各种场景,包括但不限于AOP(面向切面编程)、远程方法调用、RPC(远程 过程调用)等。通过动态代理,我们可以实现对目标方法的拦截和增强,将系统的横切关注点(如日志记录、性能统计等)与业务逻辑代码进行解耦,提高代码的可维护性和可扩展性。
3、动态代理的简单实现
这里例子还以插入订单为例,其他都不变,只需将静态代理换为动态代理就可。
public class OrderServiceImplDynamicProxy implements InvocationHandler {private Object orderService;public OrderServiceImplDynamicProxy(Object service){this.orderService = service;}public Object bind(){//创建动态代理对象return Proxy.newProxyInstance(orderService.getClass().getClassLoader(), orderService.getClass().getInterfaces(),this);}private void after() {System.out.println("动态代理对象...提交事务...");}private void before() {System.out.println("动态代理对象...开启事务...");}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();Object o = method.invoke(orderService, args);after();return o;}
}
测试
public class Test {public static void main(String[] args) {OrderService service = (OrderService)new OrderServiceImplDynamicProxy(new OrderServiceImpl()).bind();Order order = new Order();order.setInfo("xxx手机");order.setUserId("2");service.insertOrder(order);}
}/*打印结果:
动态代理对象...开启事务...
业务层...调用持久层insertOrder方法...
持久层...插入订单...Order{info='xxx手机', userId='2'}
动态代理对象...提交事务...
*/
总结
总结来说,静态代理和动态代理各有优缺点,适用于不同的场景。静态代理适用于接口稳定、功能较为简单的场景,而动态代理则适用于需要灵活代理任意实现了接口的类的场景。
相关文章:
【设计模式】之代理模式(两种)
系列文章目录 (其他设计模式可以参考 👉👉👉)设计模式_小杰不秃头的博客 😊😄😛 前言 今天继续给大家介绍23种设计模式中的代理模式,熟悉Spring的小伙伴都知道…...
【工具篇】-什么是.NET
“.NET":.NET Core是由Microsoft开发,目前在.NET Foundation(一个非营利的开源组织)下进行管理。.NET Core是用C#和C编写的,并采用MIT协议作为开源协议。 简单来说:就是开发框架。 .NET 又称 .NET 平台或 .NET 框架…...
OmniReader Pro mac激活版:智慧阅读新选择,开启高效学习之旅
在追求知识的道路上,一款优秀的阅读工具是不可或缺的。OmniReader Pro作为智慧阅读的新选择,以其独特的功能和卓越的性能,为您开启高效学习之旅。 OmniReader Pro具备高效的文本识别和处理技术,能够快速准确地提取文档中的关键信息…...
Stable Diffusion学习记录
文章目录 前言电脑配置推荐环境搭建下载地址安装步骤步骤一,打开下载的秋叶整合包,路径秋叶整合包/sd-wenui-aki步骤二,打开下载好的sd-webui-aki-v4.8.7解压包 Stable Diffusion软件配置,插件安装,模型下载Stable Dif…...
安装openssh-server,提供远程ssh
安装openssh-server,提供远程ssh 1.检查自己是否安装了openssh-server dpkg -l | grep ssh如果输出内容有openssh-server,说明已经安装过了,可以跳过下一步 2.安装openssh-server 由于ubuntu自带ssh客户端,只需要安装openssh-se…...
华纳云:选择数据库服务器你需要注意的5个原则
选择数据库服务器时,有几个关键原则需要注意,以确保选择的服务器能够满足你的需求并提供可靠的性能和安全性。 1. 性能需求 考虑你的应用程序对性能的需求,包括处理能力、内存、存储和网络带宽等方面。根据应用程序的负载和预期的并发访问量&…...
Linux动态库与静态库解析
文章目录 一、引言二、C/C源文件的编译过程三、静态库1、静态库的定义和原理2、静态库的优缺点3、静态库的创建和使用a、创建静态库b、使用静态库 四、动态库1、动态库的定义和原理2、动态库的优缺点3、动态库的创建和使用示例a、创建动态库b、使用动态库 五、动静态库的比较 一…...
后端的一些科普文章
后端开发一般有4个方面 后端开发流程 1阶段 域名认证 是每一个计算机在网络上有一个ip地址,可以通过这个地址来访问102.305.122.5(举例), 但是这个公网ip地址,比较难记忆,所以大家使用域名来更好的记忆…...
【Android学习】日期和时间选择对话框
实现功能 实现日期和时间选择的对话框,具体效果可看下图(以日期为例) 具体代码 1 日期对话框 1.1 xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android&quo…...
在Linux上使用Selenium驱动Chrome浏览器无头模式
大家好,我们平时在做UI自动化测试的时候,经常会用到Chrome浏览器的无头模式(无界面模式),并且将测试代码部署到Linux系统中执行,或者平时我们写个爬虫爬取网站的数据也会使用到,接下来和大家分享…...
Feign 第一次调用为什么会很慢?
feign调用的大致过程? Feign进行远程调用的,这里面包括,注册中心、负载均衡、FeignClient之间的关系,微服务通过不论是eureka、nacos也好注册到服务端,Feign是靠Ribbon做负载的,而Ribbon需要拿到注册中心的…...
Spring Framework-简介
Spring Framework Java Spring是一个开源的Java应用框架,它的主要目的是简化企业级应用开发的复杂性。Spring框架为开发者提供了许多基础功能,使得开发者能够更专注于业务逻辑的实现,而不是底层的细节。 主要特点和功能: 控制反…...
Linux——PHP8.0编译安装和yum安装
文章目录 Linux——PHP8.0编译安装和yum安装PHP8.0编译安装PHP8.0yum安装 Linux——PHP8.0编译安装和yum安装 PHP8.0编译安装 此内容参考于:https://www.cnblogs.com/jhno1/p/14237034.html 安装依赖 # 安装编译依赖 [rootcsq ~]# yum -y install ncurses ncurses…...
【通义千问系列】Qwen-Agent 从入门到精通【持续更新中……】
目录 前言一、快速开始1-1、介绍1-2、安装1-3、开发你自己的Agent 二、Qwen-Agent的使用和开发过程2-1、Agent2-1-1、Agent使用2-1-2、Agent开发 2-2、Tool2-2-1、工具使用2-2-2、工具开发 2-3、LLM2-3-1、LLM使用2-3-2、LLM开发 三、基于Qwen-Agent的案例分析3-1、3-2、 总结 …...
1081:分苹果
1081:分苹果 时间限制: 1000 ms 内存限制: 65536 KB 提交数:65448 通过数: 54401 【题目描述】 把一堆苹果分给n个小朋友,要使每个人都能拿到苹果,而且每个人拿到的苹果数都不同的话,这堆苹果至少应该有多少个&#x…...
Linux—-vim基础使用
1、基本概念 Vim的工作模式有四种,普通模式,输入模式,命令模式,可视模式。 在终端中打开vim,只需要输入vim 文件,在普通模式下按i就会进入到输入模式,按下:进入命令模式,输入:q就可…...
《ESP8266通信指南》12-Lua 固件烧录
往期 《ESP8266通信指南》11-Lua开发环境配置-CSDN博客 《ESP8266通信指南》10-MQTT通信(Arduino开发)-CSDN博客 《ESP8266通信指南》9-TCP通信(Arudino开发)-CSDN博客 《ESP8266通信指南》8-连接WIFI(Arduino开发…...
Covalent Network(CQT)通过 “新曙光” 计划实现重要里程碑,增强以太坊时光机,提供 30% 的年化质押收益率
Covalent Network(CQT)作为集成超过 280 条区块链,并服务于超过 2.8 亿个钱包的领先结构化数据基础设施层,宣布了其战略计划 “新曙光” 中的一个重要进展。随着网络升级并完成了准备工作的 75%,这将为即将部署的以太坊…...
JVM8参数设置相关
1、堆内存设置 JVM堆内存的设置大小应根据应用程序的具体需求和系统环境来确定。以下是一些常见的考虑因素和建议: 应用程序需求:如果应用程序需要处理大量数据或运行多个线程,那么可能需要更大的堆内存。反之,如果应用程序的需…...
送别PI-DataLink,行列视(RCV)完美替代
行列视(RCV)和 OSI PI 实时数据库自带的 PI-DataLink 报表工具,属于以实时数 据库为主要数据源的报表产品。 PI-DataLink 是专门针对 PI 实时数据库系统开发的一套 Excel 报表插件,功能强大,借助 Excel 自身的强大报表…...
新手入门:在快马上亲手实现第一个限流器,看懂‘rate limit exceeded’
最近在学习后端开发时,经常遇到"rate limit exceeded"这个错误提示。作为新手,一开始完全不明白这是什么意思,直到在InsCode(快马)平台上动手实现了一个简单的限流器,才真正理解了它的原理。今天就来分享一下这个入门项…...
10-红外接收探头电路设计实战指南
1. 红外接收探头基础入门 第一次接触红外接收探头时,我也被那一堆专业术语搞得晕头转向。其实这东西就像个"红外线翻译官",专门把遥控器发来的红外光信号转换成电信号。市面上常见的HS0038、LF0038L这些型号,本质上都是将光敏二极…...
别再只用LSTM了!试试用XGBoost给它‘打补丁’,Python时序预测精度提升实战
突破LSTM瓶颈:用XGBoost残差修正提升时序预测精度的工程实践 当你在电商平台的销量预测中,LSTM已经能捕捉到季节性波动和长期趋势,但每逢促销活动时预测总会出现明显偏差;当你在服务器负载监控中,LSTM模型对日常流量模…...
ElasticSearch数据可视化实战:用Kibana快速构建你的第一个Dashboard
ElasticSearch数据可视化实战:用Kibana快速构建你的第一个Dashboard 当你面对海量的ElasticSearch数据时,如何快速提取有价值的信息并直观呈现?Kibana作为Elastic Stack中的可视化利器,能够将复杂的数据转化为一目了然的图表和仪表…...
零基础入门:5分钟学会用Ollama运行Granite-4.0-H-350M文本生成
零基础入门:5分钟学会用Ollama运行Granite-4.0-H-350M文本生成 1. 为什么选择Granite-4.0-H-350M Granite-4.0-H-350M是一个轻量级但功能强大的文本生成模型,特别适合初学者和资源有限的用户。它只有3.5亿参数,却能在普通电脑上流畅运行&am…...
5年java开发经验总结面试题-内含完整答案
1、讲讲IO里面的常见类,字节流、字符流、接口、实现类、方法阻塞。 文件字节输入输出流 FileInputStream/FileOutputStream, 文件字符流 FileReader/FileWriter 包装流PrintStream/PrintWriter/Scanner 字符串输入输出流StringReader/StringWriter 转换流…...
嵌入式系统调试常见问题与解决方案
嵌入式系统调试中的典型问题分析与解决策略1. 常见调试问题案例分析1.1 程序文件版本错误在嵌入式开发过程中,一个常见的低级错误是使用了错误的程序文件版本。某工程师在调试时发现单片机完全不执行程序,即使是最基本的GPIO控制也无法实现。经过以下排查…...
步进电机复位翻车实录:从堵转到精准归位的5个调试技巧
步进电机复位翻车实录:从堵转到精准归位的5个调试技巧 去年夏天,我接手了一个工业自动化项目,需要精确控制12台42步进电机同步复位。本以为是个常规任务,结果第一周就遭遇了集体"罢工"——有的电机原地抖动不归零&#…...
OpenClaw跨平台同步:GLM-4.7-Flash配置在多设备复用
OpenClaw跨平台同步:GLM-4.7-Flash配置在多设备复用 1. 为什么需要跨设备同步OpenClaw配置 去年冬天,我在家里配置好OpenClaw接入GLM-4.7-Flash模型后,第二天到办公室想继续调试时,发现所有配置都要从头再来。这种重复劳动让我意…...
云原生实战:如何用GROUP模型提升容器工作负载预测准确率(附避坑指南)
云原生实战:如何用GROUP模型提升容器工作负载预测准确率(附避坑指南) 在云原生架构中,容器资源管理一直是DevOps团队面临的重大挑战。传统单容器预测方法往往忽视了微服务间复杂的协同关系,导致预测误差居高不下。本文…...
