深入理解代理模式(Proxy Pattern)及其实际应用

引言

在软件开发中,有时候我们需要在不改变现有代码的情况下添加一些功能,比如延迟初始化、访问控制、日志记录等。代理模式(Proxy Pattern)通过代理对象控制对原对象的访问,为现有代码添加了额外的功能。本篇文章将详细介绍代理模式的概念、应用场景、优缺点,并通过Java代码示例展示代理模式的实际应用。

1. 什么是代理模式?

代理模式是一种结构型设计模式,它提供一个代理对象控制对原对象的访问。代理模式可以在不修改原对象的情况下,向其添加一些功能,比如访问控制、延迟加载、日志记录等。

代理模式的结构

代理模式包含以下几个主要角色:

  • 抽象主题(Subject):定义代理类和真实主题类的公共接口。
  • 真实主题(RealSubject):实现抽象主题接口,定义真实对象。
  • 代理(Proxy):实现抽象主题接口,包含对真实主题对象的引用,并可以在调用真实主题对象前后添加额外功能。

2. 代理模式的代码示例

示例背景

假设我们有一个简单的业务服务类,它有一个方法需要在调用前后执行一些日志记录。我们可以使用代理模式来实现这一点。

抽象主题接口

首先,我们定义抽象主题接口:

// 抽象主题接口
interface BusinessService {void performTask();
}

真实主题类

然后,我们定义真实主题类:

// 真实主题类
class RealBusinessService implements BusinessService {@Overridepublic void performTask() {System.out.println("Performing the main task...");}
}

代理类

接下来,我们定义代理类,在方法调用前后执行增强内容:

// 代理类
class BusinessServiceProxy implements BusinessService {private RealBusinessService realBusinessService;public BusinessServiceProxy(RealBusinessService realBusinessService) {this.realBusinessService = realBusinessService;}@Overridepublic void performTask() {logBefore();realBusinessService.performTask();logAfter();}private void logBefore() {System.out.println("Log before method execution");}private void logAfter() {System.out.println("Log after method execution");}
}

客户端代码

最后,我们在客户端代码中使用代理模式:

public class ProxyPatternDemo {public static void main(String[] args) {RealBusinessService realBusinessService = new RealBusinessService();BusinessService businessService = new BusinessServiceProxy(realBusinessService);// 调用方法前后会执行增强内容businessService.performTask();}
}

输出

Log before method execution
Performing the main task...
Log after method execution

解释

在这个示例中,我们定义了一个业务服务接口 BusinessService 及其实现类 RealBusinessService,并通过代理类 BusinessServiceProxy 在方法调用前后添加了日志记录功能。代理类在调用真实业务服务对象的方法前后,分别调用了 logBeforelogAfter 方法,从而实现了在方法调用前后执行增强内容。

3. 代理模式在实际框架中的应用

代理模式在许多实际框架中都有广泛的应用。下面我们以Spring AOP(面向切面编程)为例,展示代理模式如何在实际应用中为现有代码添加额外功能。

案例分析:Spring AOP

Spring AOP通过代理对象为现有代码添加了日志记录、事务管理、权限控制等功能。Spring AOP可以在不修改现有代码的情况下,通过代理对象在方法调用前后添加额外的功能。

具体实现

下面是一个使用Spring AOP的示例:

1. 添加依赖

首先,在Maven的pom.xml文件中添加Spring AOP的依赖:

<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.9</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.9</version>
</dependency>
2. 目标对象

定义业务服务类:

// 目标对象
public class MyService {public void performTask() {System.out.println("Performing task...");}
}
3. 切面类

定义切面类,在方法调用前后执行增强内容:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;@Aspect
public class LoggingAspect {@Before("execution(* MyService.performTask(..))")public void logBefore() {System.out.println("Log before method execution");}@After("execution(* MyService.performTask(..))")public void logAfter() {System.out.println("Log after method execution");}
}
4. Spring 配置文件

定义Spring配置文件(aop-config.xml):

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="myService" class="MyService"/><bean id="loggingAspect" class="LoggingAspect"/><aop:config><aop:aspect ref="loggingAspect"><aop:pointcut id="performTaskPointcut" expression="execution(* MyService.performTask(..))"/><aop:before method="logBefore" pointcut-ref="performTaskPointcut"/><aop:after method="logAfter" pointcut-ref="performTaskPointcut"/></aop:aspect></aop:config>
</beans>
5. 客户端代码

在客户端代码中使用Spring AOP:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class SpringAOPDemo {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("aop-config.xml");MyService myService = (MyService) context.getBean("myService");myService.performTask();}
}

输出

Log before method execution
Performing task...
Log after method execution

解释

在这个示例中,Spring AOP通过代理对象在方法调用前后添加了日志记录功能,实现了代理模式。在Spring AOP配置文件中,我们定义了切面(Aspect)和切入点(Pointcut),并指定在目标方法调用前后执行增强内容。

4. 代理模式的优缺点

优点

  • 控制对象访问:可以在访问对象时添加额外的功能,比如权限控制、延迟加载等。
  • 增强对象功能:可以在不修改现有代码的情况下,为对象添加新的功能。
  • 灵活性高:代理对象可以灵活地控制对真实对象的访问。

缺点

  • 增加复杂性:需要引入代理对象,增加了系统的复杂性。
  • 性能开销:代理对象会增加方法调用的开销,影响系统性能。

5. 总结

代理模式通过代理对象控制对原对象的访问,为现有代码添加了额外的功能。在业务服务的示例中,我们展示了如何通过代理类在方法调用前后执行增强内容,实现了日志记录功能。在Spring AOP中的应用展示了代理模式的实际效果,极大地增强了系统的功能和灵活性。

希望这篇文章对你理解代理模式有所帮助。如果觉得本文内容有价值,请点赞、收藏和关注我们,获取更多设计模式的精彩内容!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/36661.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Three.js鼠标拖动设置骨骼姿态

实现 根据SkinnedMesh生成Mesh 作为射线检测的目标&#xff08;射线检测SkinnedMesh存在不足 无法应用骨骼形变的顶点 &#xff09;点击模型 获取点击位置对应的骨骼拖拽鼠标设置骨骼旋转角度&#xff08;使用TransformControl选中点击的骨骼 设置轴为XYZE 并隐藏控件 主动触发…

PostgreSQL计算 queryid 原理

数据库版本 PG 16.1 queryid 是什么 queryid 是将 sql 规范化 (normalization) 后&#xff0c;通过哈希函数计算出来的 64 位整数。 以 SELECT id, data FROM tbl_a WHERE id < 300 ORDER BY data; 这条 SQL 为例。当我们在 PG 中执行这条 sql 时&#xff0c;内核在语义…

图论解法:哈密顿通路问题 Leetcode 2741. 特别的排列

描述 给你一个下标从 0 开始的整数数组 nums &#xff0c;它包含 n 个 互不相同 的正整数。如果 nums 的一个排列满足以下条件&#xff0c;我们称它是一个特别的排列&#xff1a; 对于 0 < i < n - 1 的下标 i &#xff0c;要么 nums[i] % nums[i1] 0 &#xff0c;要么…

【STM32-DAP 仿真器】

STM32-DAP 仿真器 ■ STM32-DAP仿真器介绍■ STM32-DAP仿真特点■ STM32-DAP仿真器实物图■ STM32-DAP高速 DAP 仿真器实物图■ STM32-DAP高速无线调试器 实物图■ STM32-DAP高速无线调试器示意图■ STM32-DAP高速无线调试器接线图■ STM32-DAP高速无线调试器接收端示意图 ■ S…

vcruntime140_1.dll是什么东东?vcruntime140_1.dll缺失的8个解决方法

当电脑出现找不到vcruntime140_1.dll,或vcruntime140_1.dll丢失无法打开软件怎么办&#xff1f;小编今天在本文详细为大家介绍解决方法与介绍vcruntime140_1.dll究竟是什么等vcruntime140_1.dll的问题。 一、vcruntime140_1.dll文件是什么 文件概述定义与功能 vcruntime140_…

【图像增强】基于retinex实现图像增强,SSR,MSR.MSRCR,MSRCP附Matlab代码

以下是基于Retinex算法实现图像增强的几种常见方法&#xff08;SSR、MSR、MSRCR、MSRCP&#xff09;的示例Matlab代码&#xff1a; SSR&#xff08;Single-Scale Retinex&#xff09;&#xff1a; matlab function enhanced_image SSR(image, sigma) log_image log(double(…

RuoYi-Vue-Plus (代码生成、Velocity模板引擎)

一、了解Velocity JSP、Freemarker、Velocity并称3大模版技术 下面是JSP、Freemarker和Velocity的简要对比表格: 特性/技术JSPFreemarkerVelocity设计目标视图层技术,与Servlet结合模板引擎,用于生成HTML模板引擎,用于生成各种文本输出与Java集成紧密集成,可以直接编写J…

CAN收发器

1、收发器的主要功能 &#xff08;1&#xff09;CAN通讯&#xff08;即报文收发&#xff09; MCU要CAN通讯&#xff1a;收发器模式切换至正常通讯模式&#xff08;Normal&#xff09;&#xff0c;正常通讯模式收发器能收能发。 MCU不要CAN通讯&#xff1a;把收发器切换至其它…

深入理解SQL优化:理论与实践的结合

深入理解SQL优化&#xff1a;理论与实践的结合 SQL优化是数据库性能优化的核心&#xff0c;通过优化SQL查询&#xff0c;可以极大地提高数据库的响应速度和资源利用效率。本文将以SQL优化的理论基础和实践应用为主线&#xff0c;结合具体案例&#xff0c;系统化地介绍如何有效…

format()函数

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法介绍 format()可以对数据进行格式化处理操作&#xff0c;语法如下&#xff1a; format(value, format_spec) format_spec为格式化解释。当参数…

C++ STL Custom Iterator 自定义迭代器

#include <iostream> #include <iterator> #include <algorithm> class MyArray { public://演示自定义迭代器struct Iterator{/*第一步: 需要实现以下几种属性,这些属性是C++实现迭代器的约定,确保STL库算法可以使用该自定义迭代器 *///指定…

C语言笔记26 •顺序表应用•

基于动态顺序表实现通讯录项目 1.通讯录其实也就是顺序表&#xff0c;就是把里面存的数据类型变了一下 &#xff0c;所以有一些方法对于顺序表适用&#xff0c;对于通讯录也是适用的&#xff08;初始化&#xff0c;销毁&#xff0c;内存空间扩容&#xff09;。 2.要用到顺序表…

解决镜像加速问题

一、加速解决方案 -- 针对 Docker 运行时 1.1、配置阿里云镜像加速器 阿里云提供了免费使用的镜像加速服务。以下是具体的配置步骤&#xff1a; 登录到阿里云控制台 https://cr.console.aliyun.com/ 进入“镜像中心”&#xff0c;点击左侧菜单中的“镜像加速器”。 将页面中…

【设计模式】行为型-策略模式

策略模式&#xff0c;如春风吹过&#xff0c;随心所欲&#xff0c;变幻无穷&#xff0c;每一丝风都是一种选择。 文章目录 一、订单处理二、策略模式三、策略模式的核心组成四、运用策略模式五、策略模式的应用场景六、小结推荐阅读 一、订单处理 场景假设&#xff1a;有一个…

MySQL高级-索引-设计原则小结

文章目录 1、设计原则2、索引小结2.1、索引概述2.2、索引结构2.3、索引分类2.4、索引语法2.5、SQL性能分析2.6、索引使用2.7、索引设计原则 1、设计原则 针对于数据量较大&#xff0c;且查询比较频繁的表建立索引。针对于常作为查询条件&#xff08;where&#xff09;、排序&am…

2毛钱的SOT23-5封装28V、1.5A、1.2MHz DCDC转换器用于LCD偏置电源和白光LED驱动等MT3540升压芯片

前言 之前发了一个TI的BOOST升压芯片&#xff0c;用于LCD偏置电压或LED驱动&#xff0c;请访问以下链接。 6毛钱SOT-23封装28V、400mA 开关升压转换器&#xff0c;LCD偏置电源和白光LED应用芯片TPS61040 国产半导体厂家发展迅猛&#xff0c;今天推荐一个公司带“航天”的升压…

Java基础知识整理笔记

目录 1.关于Java概念 1.1 谈谈对Java的理解&#xff1f; 1.2 Java的基础数据类型&#xff1f; 1.3 关于面向对象的设计理解 1.3.1 面向对象的特性有哪些&#xff1f; 1.3.2 重写和重载的区别&#xff1f; 1.3.3 面向对象的设计原则是什么&#xff1f; 1.4 关于变量与方…

187. 导弹防御系统

Powered by:NEFU AB-IN Link 文章目录 187. 导弹防御系统题意思路代码 187. 导弹防御系统 题意 为了对抗附近恶意国家的威胁&#xff0c;R国更新了他们的导弹防御系统。 一套防御系统的导弹拦截高度要么一直 严格单调 上升要么一直 严格单调 下降。 例如&#xff0c;一套系…

代码随想录算法训练营第五十天 | 1143.最长公共子序列、1035.不相交的线、53. 最大子序和、392.判断子序复习

1143.最长公共子序列 题目链接&#xff1a;https://leetcode.cn/problems/longest-common-subsequence/ 文档讲解&#xff1a;https://programmercarl.com/1143.%E6%9C%80%E9%95%BF%E5%85%AC%E5%85%B1… 视频讲解&#xff1a;https://www.bilibili.com/video/BV1ye4y1L7CQ 最近…

swagger访问路径

Swagger 2.x 版本 访问地址&#xff1a;http://{ip}:{port}/{context-path}/swagger-ui.html {ip} 是你的服务器IP地址。 {port} 是你的应用服务端口&#xff0c;通常为8080。 {context-path} 是你的应用上下文路径&#xff0c;如果应用部署在根路径下&#xff0c;则为空。 …