GPT带我学-设计模式-代理模式

什么是代理模式

代理模式(Proxy Pattern)是设计模式中的一种结构型模式,它为其他对象提供一种代理以控制对这个对象的访问。

代理模式有三个主要角色:抽象主题(Subject)、真实主题(Real Subject)和代理(Proxy)。

抽象主题(Subject):定义了真实主题与代理之间的共同接口,这样真实主题和代理可以互相替换使用。

真实主题(Real Subject):指实际要被代理的对象。

代理(Proxy):提供了一个与真实主题相同的接口,它内部持有一个真实主题的引用,并在真实主题的实例化或执行某些操作前后进行控制或扩展。

代理模式的主要目的是在不改变真实主题的情况下,为其提供一个代理类来进行访问控制或增强功能。代理模式可以实现懒加载,即在真正需要使用真实主题的时候才进行实例化,从而节省资源和提高性能。代理模式还能提供额外的功能,例如在调用真实主题的方法前后进行日志记录、安全控制、事务管理等。

代理模式可以分为静态代理和动态代理。静态代理是通过手动编写代理类来实现的,而动态代理则是在运行时动态生成代理类。动态代理通常使用Java的反射机制来实现,可以减少冗余代码,并且对真实主题的访问完全透明。

总之,代理模式提供了一种间接访问对象的方式,可以控制对象的访问、增强对象的功能,并且可以在不改变真实对象的情况下进行扩展。

代理模式有几种形式

在设计模式中,代理模式有两种常见的形式:

静态代理(Static Proxy):静态代理需要手动编写代理类,代理类和真实主题类实现相同的接口或继承相同的父类,并在代理类中持有一个真实主题类的引用。静态代理在编译时就确定了代理对象和真实对象的关系。

动态代理(Dynamic Proxy):动态代理在运行时动态生成代理类,不需要手动编写代理类。Java中的动态代理通常使用Java反射机制实现,可以通过Proxy类和InvocationHandler接口来创建动态代理对象。动态代理可以代理接口或类,适用于需要代理多个不同类型对象的场景。

在静态代理和动态代理中,代理类都是通过调用真实主题类的方法,并在方法前后加上一些额外的逻辑(如日志记录、权限验证等)来控制或增强真实主题的功能。

除了静态代理和动态代理,还有一些其他的代理变体形式,如远程代理、虚拟代理、保护代理等,这些形式根据具体的应用场景和需求进行使用。

请举一个具体的静态代理例子

假设有一个接口 Subject,定义了一个抽象主题的操作方法 request()。现在我们需要用静态代理来实现在真实主题的执行前后进行日志记录。

首先,定义一个 Subject 接口:

public interface Subject {void request();
}

接下来,创建真实主题类 RealSubject,实现 Subject 接口:

public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("真实主题执行请求");}
}

然后,创建一个代理类 ProxySubject,实现 Subject 接口,并在 request() 方法的前后添加日志记录的逻辑:

public class ProxySubject implements Subject {private RealSubject realSubject;public ProxySubject(RealSubject realSubject) {this.realSubject = realSubject;}@Overridepublic void request() {System.out.println("代理主题执行请求之前的日志记录");// 调用真实主题的方法realSubject.request();System.out.println("代理主题执行请求之后的日志记录");}
}

最后,我们可以通过以下代码来使用静态代理:

public class Main {public static void main(String[] args) {RealSubject realSubject = new RealSubject();ProxySubject proxy = new ProxySubject(realSubject);proxy.request();}
}

运行程序,输出结果如下:

代理主题执行请求之前的日志记录
真实主题执行请求
代理主题执行请求之后的日志记录

可以看到,通过静态代理模式,我们在真实主题的执行前后添加了日志记录的逻辑,实现了对真实主题的控制和功能增强,而不需要修改真实主题类的代码。这是静态代理模式的一种常见应用场景。

同样的例子怎么改成动态代理模式呢

要将上述示例改为动态代理模式,需使用Java的动态代理实现。首先,需要借助 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。

首先,定义 Subject 接口和 RealSubject 真实主题类,与上述示例相同。

接下来,创建一个实现 InvocationHandler 接口的代理处理器类 ProxyHandler,用于在真实主题的方法执行前后添加日志记录的逻辑。在 invoke() 方法中,可以定义增强的逻辑以及调用真实主题的方法。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class ProxyHandler implements InvocationHandler {private Object realSubject;public ProxyHandler(Object realSubject) {this.realSubject = realSubject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理主题执行请求之前的日志记录");// 调用真实主题的方法Object result = method.invoke(realSubject, args);System.out.println("代理主题执行请求之后的日志记录");return result;}
}

最后,可以通过以下代码来使用动态代理:

import java.lang.reflect.Proxy;public class Main {public static void main(String[] args) {RealSubject realSubject = new RealSubject();InvocationHandler handler = new ProxyHandler(realSubject);// 创建动态代理对象Subject proxySubject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),realSubject.getClass().getInterfaces(),handler);proxySubject.request();}
}

运行程序,输出结果与静态代理的例子相同:

代理主题执行请求之前的日志记录
真实主题执行请求
代理主题执行请求之后的日志记录

可以看到,通过动态代理模式,我们实现了在真实主题的执行前后添加日志记录的逻辑,而不需要直接操作代理类,使代理对象动态生成,并且能够透明地调用真实主题的方法。这是动态代理模式的一种常见应用场景。

补充说明(《Head First设计模式》)

java在java.lang.reflect包中有自己的代理实现方式,通过相关api可以动态创建一个代理类。
通过代理类去调用被代理的方法。
因为实际代理类是在运行时创建的,所以把java的这个技术叫做动态代理。
Java为我们动态创建了Proxy。我们通过实现InvocationHandler接口告诉Proxy去做什么。

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

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

相关文章

Springboot 实践(9)springboot集成Oauth2.0授权包,5个接口文件配置详解

前文讲解实现了spring boot集成Oauth2.0,实现了授权服务器和资源服务器的搭建,并通过浏览器和postman测试,获取到了授权码,用携带授权码的URL能够争取范文到资源。 本文详细讲解spring boot集成Oauth2.0的几个重要文件接口&#…

【开个空调】语音识别+红外发射

废话少说,直接上空调板子:YAPOF3。红外接收发射模块用的某宝上发现的YF-33(遗憾解码还没搞清楚,不然做个lirc.conf功能才多)。最后是语音识别用的幻尔的,某宝自然也有,它是个i2c的接口。 本篇胡说八道其实纯粹为了留个…

python 无网络安装库的方法

手动复制库文件: 在你的电脑上找到已安装库的文件,通常位于Python的Lib\site-packages目录下。将这些库文件复制到目标电脑的相同位置。请注意,这种方法仅适用于纯Python库,对于依赖于C扩展或其他系统依赖项的库可能无法正常工作。…

华为云Stack的学习(一)

一、华为云Stack架构 1.HCS 物理分散、逻辑统一、业务驱动、运管协同、业务感知 2.华为云Stack的特点 可靠性 包括整体可靠性、数据可靠性和单一设备可靠性。通过云平台的分布式架构,从整体系统上提高可靠性,降低系统对单设备可靠性的要求。 可用性…

Java后端开发面试题篇——Redis

Redis的数据持久化策略有哪些 RDB的执行原理? bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件。 fork采用的是copy-on-write技术: 当主进程执行读操作时,访问共享内存…

实现外网访问本地服务

最近开发需要其他项目组的人访问我本地服务测试,但又不在同一个地方,不能使用内网访问,所以需要外网访问本地服务功能. 条件: 1.需要一台具备公网IP的服务器 我用的服务器是windows,电脑也是Windows系统 2.下载frp 软件,只需要下载一份就可以了,分别放到服务器上和本地目录既…

无涯教程-PHP - Session选项

从PHP7 起, session_start()()函数接受一系列选项,以覆盖在 php.ini 中设置的会话配置指令。这些选项支持 session.lazy_write ,默认情况下此函数为on,如果会话数据已更改,则会导致PHP覆盖任何会话文件。 添加的另一个…

TCP网络连接异常情况的处理

在网络连接中,经常会出现一些意外情况,导致TCP连接不能正常工作,对于这些意外情况,TCP内部有自己的解决方法 一.进程崩溃 在网络通讯时可能会出现进程突然崩溃的情况,当进程崩溃后进程就没了,就会导致进程…

Java实现一个简单的图书管理系统(内有源码)

简介 哈喽哈喽大家好啊,之前作者也是讲了Java不少的知识点了,为了巩固之前的知识点再为了让我们深入Java面向对象这一基本特性,就让我们完成一个图书管理系统的小项目吧。 项目简介:通过管理员和普通用户的两种操作界面&#xff0…

主力吸筹指标及其分析和使用说明

文章目录 主力吸筹指标指标代码分析使用说明使用配图主力吸筹指标 VAR1:=REF(LOW,1); VAR2:=SMA(MAX(LOW-VAR1,0),3,1)/SMA(ABS(LOW-VAR1),3,1)*100; VAR3:=EMA(VAR2,3); VAR4:=LLV(LOW,34); VAR5:=HHV(VAR3,34); VAR7:=EMA(IF(LOW<=VAR4,(VAR3+VAR5*2)/2,0),3); /*底线:0,…

让eslint的错误信息显示在项目界面上

1.需求描述 效果如下 让eslint中的错误&#xff0c;显示在项目界面上 2.问题解决 1.安装 vite-plugin-eslint 插件 npm install vite-plugin-eslint --save-dev2.配置插件 // vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue import e…

基于黄金正弦算法优化的BP神经网络(预测应用) - 附代码

基于黄金正弦算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于黄金正弦算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.黄金正弦优化BP神经网络2.1 BP神经网络参数设置2.2 黄金正弦算法应用 4.测试结果&#xff1a;5…

C语言练习1(巩固提升)

C语言练习1 选择题 前言 “人生在勤&#xff0c;勤则不匮。”幸福不会从天降&#xff0c;美好生活靠劳动创造。全面建成小康社会的奋斗目标&#xff0c;为广大劳动群众指明了光明的未来&#xff1b;全面建成小康社会的历史任务&#xff0c;为广大劳动群众赋予了光荣的使命&…

采用typescript编写,实现ofd前端预览、验章

前言 浏览器内核已支持pdf文件的渲染&#xff0c;这极大的方便了pdf文件的阅读和推广。ofd文件作为国产板式标准&#xff0c;急需一套在浏览器中渲染方案。 本人研究ofd多年&#xff0c;分别采用qt、c# 开发了ofd阅读器。本人非前端开发人员&#xff0c;对js、typescript并不熟…

android Bitmap没有recycle()导致native内存暴增

android Bitmap没有recycle()导致native内存暴增 android8.0后&#xff0c;Bitmap从Java层转移到native层&#xff0c;此举虽然缓解了JVM的内存压力&#xff0c;也提升了图形的加载速度&#xff0c;但不恰当的Bitmap分配/释放逻辑&#xff0c;将导致内存问题深藏到native层&am…

windows开发环境搭建

下载msys2&#xff0c;官网下载即可&#xff1a; MSYS2 安装其他的编译工具&#xff08;貌似不需要把中间的命令全部执行&#xff09;&#xff1a; MSYS2使用教程——win10系统64位安装msys2最新版&#xff08;msys2-x86_xxxx.exe&#xff09;_msys64_Dreamhai的博客-CSDN博…

Maven 一键部署到 SSH 服务器

简介 利用 Maven Mojo 功能一键部署 jar 包或 war 包到远程服务器上。 配置 在 maven 的setting.xml 配置服务器 SSH 账号密码。虽然可以在工程的 pom.xml 直接配置&#xff0c;但那样不太安全。 <servers><server><id>iq</id><configuration&…

【C++代码】有序数组的平方,长度最小的子数组,螺旋矩阵 II--代码随想录

题目&#xff1a;有序数组的平方 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 题解 数组其实是有序的&#xff0c; 只不过负数平方之后可能成为最大数了。那么数组平方的最大值就在数组的…

食品制造行业云MES系统解决方案

食品饮料行业大致可以分为初级产品加工、二次加工、食品制造、食品分装、调味品和饲料加工等几大类。由于处于产业链不同的位置&#xff0c;其管理存在一定的差异&#xff0c;那么食品行业的MES应该怎么建设呢&#xff1f; 食品饮料行业生产管理特点&#xff1a; 食品饮料行业…

定时任务,Timer,Quartz,Spring Task,Xxl-Job(分布式任务调度框架)

一、定时任务解决方案 1.Thread&#xff0c;Timer&#xff0c;Quartz&#xff0c;Spring Task Thread线程等待&#xff08;最原始最简单方式&#xff09;&#xff0c;创建一个thread&#xff0c;然后让它在while循环里一直运行着&#xff0c;通过sleep方法来达到定时任务的效…