Java结构型模式---代理模式

代理模式基础概念

代理模式是一种结构型设计模式,其核心思想是通过创建一个代理对象来控制对另一个真实对象的访问。代理对象在客户端和真实对象之间起到中介作用,允许在不改变真实对象的前提下,对其进行增强或控制。

代理模式的核心组件

  1. 主题接口 (Subject) - 定义真实对象和代理对象的共同接口,客户端通过该接口访问真实对象
  2. 真实主题 (RealSubject) - 实现主题接口,是实际要被代理的对象
  3. 代理 (Proxy) - 实现主题接口,持有真实主题的引用,在调用真实主题方法前后可以添加额外逻辑

静态代理实现

静态代理是指在编译时就已经确定代理类和被代理类的关系,代理类需要手动编写。

// 主题接口
interface Image {void display();void resize();
}// 真实主题
class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadFromDisk(fileName);}@Overridepublic void display() {System.out.println("Displaying " + fileName);}@Overridepublic void resize() {System.out.println("Resizing " + fileName);}private void loadFromDisk(String fileName) {System.out.println("Loading " + fileName);}
}// 代理类
class ProxyImage implements Image {private RealImage realImage;private String fileName;public ProxyImage(String fileName) {this.fileName = fileName;}@Overridepublic void display() {// 延迟加载:在需要显示时才创建真实对象if (realImage == null) {realImage = new RealImage(fileName);}// 可以在调用真实对象方法前后添加额外逻辑System.out.println("Before displaying");realImage.display();System.out.println("After displaying");}@Overridepublic void resize() {if (realImage == null) {realImage = new RealImage(fileName);}System.out.println("Before resizing");realImage.resize();System.out.println("After resizing");}
}// 客户端代码
public class StaticProxyClient {public static void main(String[] args) {Image image = new ProxyImage("test.jpg");// 第一次调用display,会加载图片并显示System.out.println("First call to display:");image.display();// 第二次调用display,不会重新加载图片System.out.println("\nSecond call to display:");image.display();// 调用resize方法System.out.println("\nCall to resize:");image.resize();}
}

动态代理实现

动态代理是指在运行时通过反射机制动态生成代理类,无需手动编写。Java 提供了java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler来实现动态代理。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 主题接口
interface UserService {void createUser(String username);void deleteUser(int userId);String getUser(int userId);
}// 真实主题
class UserServiceImpl implements UserService {@Overridepublic void createUser(String username) {System.out.println("Creating user: " + username);}@Overridepublic void deleteUser(int userId) {System.out.println("Deleting user with ID: " + userId);}@Overridepublic String getUser(int userId) {System.out.println("Getting user with ID: " + userId);return "User" + userId;}
}// 动态代理处理器
class LoggingHandler implements InvocationHandler {private final Object target; // 真实对象public LoggingHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 方法调用前的日志记录System.out.println("Before method: " + method.getName());if (args != null) {for (int i = 0; i < args.length; i++) {System.out.println("  Arg " + (i + 1) + ": " + args[i]);}}// 调用真实对象的方法Object result = method.invoke(target, args);// 方法调用后的日志记录System.out.println("After method: " + method.getName());return result;}
}// 客户端代码
public class DynamicProxyClient {public static void main(String[] args) {// 创建真实对象UserService userService = new UserServiceImpl();// 创建InvocationHandlerInvocationHandler handler = new LoggingHandler(userService);// 创建动态代理对象UserService proxyService = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),new Class<?>[]{UserService.class},handler);// 调用代理对象的方法proxyService.createUser("John Doe");System.out.println();String user = proxyService.getUser(123);System.out.println("Returned user: " + user);System.out.println();proxyService.deleteUser(123);}
}

CGLIB 代理实现

CGLIB 是一个强大的、高性能的代码生成库,可以在运行时扩展 Java 类与实现 Java 接口。当需要代理没有实现接口的类时,可以使用 CGLIB 代理。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;// 没有实现接口的目标类
class CustomerService {public void saveCustomer(String name) {System.out.println("Saving customer: " + name);}public String getCustomer(int id) {System.out.println("Getting customer with ID: " + id);return "Customer" + id;}
}// CGLIB方法拦截器
class CustomerServiceInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method: " + method.getName());// 调用父类(即目标类)的方法Object result = proxy.invokeSuper(obj, args);System.out.println("After method: " + method.getName());return result;}
}// 客户端代码
public class CglibProxyClient {public static void main(String[] args) {// 创建Enhancer对象Enhancer enhancer = new Enhancer();// 设置要代理的目标类enhancer.setSuperclass(CustomerService.class);// 设置回调函数enhancer.setCallback(new CustomerServiceInterceptor());// 创建代理对象CustomerService proxy = (CustomerService) enhancer.create();// 调用代理对象的方法proxy.saveCustomer("Alice");System.out.println();String customer = proxy.getCustomer(456);System.out.println("Returned customer: " + customer);}
}

代理模式的应用场景

  1. 远程代理 - 为一个位于不同地址空间的对象提供本地代理
  2. 虚拟代理 - 延迟创建开销大的对象,如图片懒加载
  3. 保护代理 - 控制对原始对象的访问,用于权限管理
  4. 缓存代理 - 缓存对资源的访问结果,提高性能
  5. 智能引用代理 - 在访问对象时附加额外操作,如引用计数

静态代理与动态代理的对比

特性静态代理动态代理
代理类创建时间编译时运行时
代码复杂度高,需手动编写每个代理类低,通过反射动态生成
可维护性低,接口修改时需同步修改代理类高,自动适配接口变化
灵活性低,只能代理特定接口或类高,可以代理任意实现接口的类
性能稍高,无需反射稍低,依赖反射调用
适用场景简单场景,代理类数量少复杂场景,需要灵活的代理机制

代理模式的优缺点

优点

  • 降低耦合度 - 客户端与真实对象解耦
  • 增强扩展性 - 可以在不修改真实对象的情况下增强功能
  • 控制访问 - 可以对真实对象的访问进行控制
  • 提高性能 - 通过缓存等机制提升性能

缺点

  • 增加系统复杂度 - 引入代理对象,可能使系统变得复杂
  • 性能开销 - 动态代理使用反射,可能带来性能损失
  • 调试困难 - 代理逻辑可能分散在多个地方,增加调试难度

使用代理模式的注意事项

  1. 合理选择代理类型 - 根据需求选择静态代理、动态代理或 CGLIB 代理
  2. 接口设计 - 设计良好的主题接口,确保代理和真实对象行为一致
  3. 代理链 - 可以组合多个代理形成代理链,实现更复杂的功能
  4. 性能考虑 - 对于性能敏感的应用,需谨慎使用动态代理
  5. 兼容性 - CGLIB 代理不能用于 final 类或方法,因为无法被继承

代理模式是一种非常实用的设计模式,它通过引入代理对象来控制对真实对象的访问,提供了增强功能、控制访问和提高性能的能力。在实际开发中,动态代理和 CGLIB 代理更为常用,它们提供了更灵活的代理机制。

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

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

相关文章

MySQL流程控制函数全解析

MySQL 中的流程控制函数&#xff08;也称为条件函数&#xff09;允许你在 SQL 语句中进行逻辑判断&#xff0c;根据不同的条件返回不同的值或执行不同的操作。它们极大地增强了 SQL 的灵活性和表达能力&#xff0c;尤其在进行数据转换、结果格式化、条件聚合和复杂业务逻辑实现…

【7】PostgreSQL 事务

【7】PostgreSQL 事务前言使用事务事务内错误处理事务保存点DDL 事务前言 在 PostgreSQL 中&#xff0c;每一个操作都是一个事务。即使一个简单的查询(select)&#xff0c;这也是一个事务。 例如&#xff1a; postgres# select now();now --------------------…

Linux:多线程---深入互斥浅谈同步

文章目录1. 互斥1.1 为什么需要互斥1.2 互斥锁1.3 初谈互斥与同步1.4 锁的原理1.5 可重入VS线程安全1.6 死锁1.7 避免死锁的算法&#xff08;扩展&#xff09;序&#xff1a;在上一章中我们知道了线程控制的三个角度&#xff1a;线程创建、线程等待和线程终止&#xff0c;分别从…

适用于 vue2、vue3 的自定义指定:v-int(正整数)

在项目中&#xff0c;我们经常会遇到输入框只允许输入数字的情况&#xff0c;下面是一段自定义指定 代码&#xff0c;复制到项目中&#xff0c;注册指定即可使用用法如下&#xff1a; 创建一个IntInput.js 文件&#xff0c;将下面代码复制到文件中保存在项目中的 main.js 文件中…

学习基于springboot秒杀系统-环境配置(接口封装,mybatis,mysql,redis(Linux))

文章目录前言创建springboot项目封装controller层输入输出rest api 的json输出返回页面集成mybatis集成redis下载虚拟机和centos下载redis.tar.gz上传redis.tar.gz 到虚拟机前言 今天开始记录学习秒杀系统-课程是基于慕课上的搜索秒杀系统的课程&#xff0c;老师讲解非常好。这…

stm32达到什么程度叫精通?

STM32达到什么程度叫精通&#xff1f;一个十年老兵的深度反思 前言&#xff1a;精通二字&#xff0c;重如泰山 每次有人问我"STM32达到什么程度叫精通"这个问题&#xff0c;我都会沉默很久。 不是因为这个问题难回答&#xff0c;而是因为"精通"这两个字太重…

微软上线Deep Research:OpenAI同款智能体,o3+必应双王炸

今天凌晨&#xff0c;微软在官网宣布&#xff0c;Azure AI Foundry中上线Deep Research公开预览版。这是支持API和SDK的OpenAI 高级智能体研究能力产品&#xff0c;并且Azure 的企业级智能体平台完全集成。Deep Research是OpenAI在今年4月25日发布的最新产品&#xff0c;能够像…

Spring Batch终极指南:原理、实战与性能优化

&#x1f31f; Spring Batch终极指南&#xff1a;原理、实战与性能优化单机日处理10亿数据&#xff1f;揭秘企业级批处理架构的核心引擎&#xff01;一、Spring Batch 究竟是什么&#xff1f;Spring batch是用于创建批处理应用程序&#xff08;执行一系列作业&#xff09;的开源…

【Part 3 Unity VR眼镜端播放器开发与优化】第四节|高分辨率VR全景视频播放性能优化

文章目录《VR 360全景视频开发》专栏Part 3&#xff5c;Unity VR眼镜端播放器开发与优化第一节&#xff5c;基于Unity的360全景视频播放实现方案第二节&#xff5c;VR眼镜端的开发适配与交互设计第三节&#xff5c;Unity VR手势交互开发与深度优化第四节&#xff5c;高分辨率V…

TCP/IP协议基础

TCPIP协议基础 网络模型 -OSI参考模型 -OSI参考模型各层功能 -TCP/IP网络模型 -TCP/IP协议栈OSI参考模型 – 为了解决网络设备之间的兼容性问题&#xff0c;国际标准化组织ISO于1984年提出了OSI RM&#xff08;开放系统互连参考模型&#xff09;。 OSI参考模型一共有七层&#…

【Nginx】Nginx代理WebSocket

1.websocketWebSocket 是一种网络通信协议&#xff0c;它提供了在单个 TCP 连接上进行全双工&#xff08;双向&#xff09;通信的能力假设需求&#xff1a;把 ws://192.168.0.1:8088/ws-api/websocket/pushData代理到ws://192.168.0.156:8888/websocket/pushData&#xff1b;同…

Spring AI Alibaba Graph使用案例人类反馈

1、Spring AI Alibaba Graph 是社区核心实现之一&#xff0c;也是整个框架在设计理念上区别于 Spring AI 只做底层原子抽象的地方&#xff0c;Spring AI Alibaba 期望帮助开发者更容易的构建智能体应用。基于 Graph 开发者可以构建工作流、多智能体应用。Spring AI Alibaba Gra…

本地部署jenkins持续集成

一、准备环境&#xff08;jdk版本跟Tomcat版本要匹配&#xff09; java jdk 环境(版本是11.0.21) jenkins war包(版本是2.440.3) Tomcat (版本是 9.0.84) 二、安装步骤 1、安装jdk环境 1&#xff09;先安装java环境&#xff0c;安装完成后配置环境变量&#xff0c;参考上…

基于Java+Maven+Testng+Selenium+Log4j+Allure+Jenkins搭建一个WebUI自动化框架(1)搭建框架基本雏形

本次框架使用Maven作为代码构建管理&#xff0c;引用了PO模式&#xff0c;将整体的代码分成了页面层、用例层、业务逻辑层。框架搭建流程&#xff1a;1、在pom.xml中引入依赖&#xff1a;<!-- https://mvnrepository.com/artifact/io.appium/java-client --> <depende…

从零构建MCP服务器:FastMCP实战指南

引言&#xff1a;MCP协议与FastMCP框架 Model Context Protocol&#xff08;MCP&#xff09;是连接AI模型与外部服务的标准化协议&#xff0c;允许LLM&#xff08;如Claude、Gemini&#xff09;调用工具、访问数据。然而&#xff0c;直接实现MCP协议需要处理JSON-RPC、会话管理…

基于FPGA的智能小车设计(包含代码)/ 全栈FPGA智能小车:Verilog实现蓝牙/语音/多传感器融合的移动平台

首先先声明一下&#xff0c;本项目已经历多轮测试&#xff0c;可以放心根据我的设计进行二次开发和直接套用&#xff01;&#xff01;&#xff01; 代码有详细的注释&#xff0c;方便同学进行学习&#xff01;&#xff01; 制作不易&#xff0c;记得三连哦&#xff0c;给我动…

Object.defineProperties 详解

Object.defineProperties 详解 Object.defineProperties 是 JavaScript 中用于在一个对象上定义或修改多个属性的方法。它是 Object.defineProperty 的复数版本&#xff0c;允许你一次性定义多个属性。 基本语法 Object.defineProperties(obj, props)obj&#xff1a;要在其上定…

MyBatis-Plus:深入探索与最佳实践

MyBatis-Plus作为MyBatis的增强版&#xff0c;已经在Java开发中得到了广泛应用。它不仅继承了MyBatis的所有功能&#xff0c;还提供了许多强大的扩展功能&#xff0c;帮助开发者提升开发效率和代码质量。本文将深入探讨MyBatis-Plus的高级特性及其在实际项目中的最佳实践。一、…

劳斯莱斯数字孪生技术:重构航空发动机运维的绿色革命

在航空工业迈向智能化的浪潮中&#xff0c;劳斯莱斯以数字孪生技术为核心&#xff0c;构建了发动机全生命周期管理的创新范式。这项技术不仅重新定义了航空发动机的维护策略&#xff0c;更通过数据驱动的决策体系&#xff0c;实现了运营效率与生态效益的双重突破。本文将从技术…