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

【设计模式】-代理模式

在软件开发中,经常遇到需要对某个对象进行控制或者监控的场景。而直接修改对象的代码可能使代码变得复杂且难以维护。这时,使用代理模式(Proxy Pattern)可以很好地解决这个问题。

         代理模式是一种结构型设计模式,通过引入一个代理对象来替代原始对象,实现对原有对象的控制或扩展。Java中的代理模式常用于实现日志记录权限控制事务控制等功能。


原理及实现思路

代理模式的核心思想是通过引入代理对象作为中间层,将客户端的请求转发给真正的对象,从而实现对真实对象的控制。

代理模式包含三个主要角色:

  • 抽象主题(Subject):定义了代理对象和真实对象的共同接口。

  • 真实主题(RealSubject):实现了抽象主题接口,是真正的业务逻辑处理对象。

  • 代理主题(ProxySubject):实现了抽象主题接口,内部持有一个真实主题对象的引用,通过代理对象间接调用真实对象。

实现代理模式的步骤如下:

  1. 创建抽象主题接口,定义需要代理的方法。

  2. 创建真实主题类,实现抽象主题接口,完成真正的业务逻辑。

  3. 创建代理主题类,实现抽象主题接口,持有一个真实主题对象的引用,在代理方法中调用真实主题的方法。

静态代理

        静态代理是最简单的一种代理技术,由程序员手动编写代理类来代替真实对象。静态代理在编译期生成代理类,在运行时代理类不会发生变化

        静态代理的优点是简单易懂、易于实现,但缺点也显而易见,每个代理类只能代理一个具体类,当代理类的数量较多时,会导致代码冗余,并且每个代理类只能代理一个固定的类

示例代码如下:

// 抽象主题接口
interface Subject {void doSomething();
}// 真实主题类
class RealSubject implements Subject {@Overridepublic void doSomething() {System.out.println("RealSubject do something.");}
}// 代理主题类
class ProxySubject implements Subject {private Subject realSubject;public ProxySubject(Subject realSubject) {this.realSubject = realSubject;}@Overridepublic void doSomething() {// 对真实主题方法的增强System.out.println("Before do something.");realSubject.doSomething();System.out.println("After do something.");}
}// 客户端代码
public class Client {public static void main(String[] args) {RealSubject realSubject = new RealSubject();ProxySubject proxySubject = new ProxySubject(realSubject);proxySubject.doSomething();}
}

动态代理

        动态代理是在运行时动态地生成代理对象,相比于静态代理,动态代理更加灵活。Java中提供了两种动态代理的实现方式:基于接口的动态代理基于类的动态代理

        基于接口的动态代理使用java.lang.reflect.Proxy类以及java.lang.reflect.InvocationHandler接口来实现。

        这种方式要求被代理类实现一个接口,并通过代理类来间接调用真实对象的方法。

示例代码如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 抽象主题接口
interface Subject {void doSomething();
}// 真实主题类
class RealSubject implements Subject {@Overridepublic void doSomething() {System.out.println("RealSubject do something.");}
}// InvocationHandler实现类
class MyInvocationHandler implements InvocationHandler {private Object realSubject;public MyInvocationHandler(Object realSubject) {this.realSubject = realSubject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 对真实主题方法的增强System.out.println("Before do something.");Object result = method.invoke(realSubject, args);System.out.println("After do something.");return result;}
}// 客户端代码
public class Client {public static void main(String[] args) {RealSubject realSubject = new RealSubject();InvocationHandler handler = new MyInvocationHandler(realSubject);Subject proxySubject = (Subject) Proxy.newProxyInstance(Client.class.getClassLoader(),new Class[]{Subject.class},handler);proxySubject.doSomething();}
}

基于类的动态代理使用cglib库,不要求被代理类实现接口,通过生成子类来实现代理。

示例代码如下:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;// 真实主题类
class RealSubject {public void doSomething() {System.out.println("RealSubject do something.");}
}// MethodInterceptor实现类
class MyMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {// 对真实主题方法的增强System.out.println("Before do something.");Object result = methodProxy.invokeSuper(object, args);System.out.println("After do something.");return result;}
}// 客户端代码
public class Client {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(RealSubject.class);enhancer.setCallback(new MyMethodInterceptor());RealSubject proxySubject = (RealSubject) enhancer.create();proxySubject.doSomething();}
}

不同代理模式的优缺点及适用场景

优缺点

  • 静态代理的优点在于简单易懂、易于实现。缺点是每个代理类只能代理一个具体类,导致代码冗余,不够灵活。

  • 基于接口的动态代理的优点是可以代理实现了指定接口的任意对象,不需要修改原有代码。缺点是只能代理接口中定义的方法。

  • 基于类的动态代理的优点是可以代理任意类的对象,不需要修改原有代码。缺点是不能代理final修饰的类和方法。

适用场景:

  • 静态代理适用于只需要代理少数几个类,并且不需要频繁地修改代理类的情况。

  • 基于接口的动态代理适用于需要对接口中的方法进行控制和扩展的情况。

  • 基于类的动态代理适用于不需要修改原有代码、对类的任意方法进行控制和扩展的情况。

相关文章:

【设计模式】-代理模式

在软件开发中,经常遇到需要对某个对象进行控制或者监控的场景。而直接修改对象的代码可能使代码变得复杂且难以维护。这时,使用代理模式(Proxy Pattern)可以很好地解决这个问题。 代理模式是一种结构型设计模式,通过引…...

爬虫ip池越大越好吗?

作为一名资深的程序员,今天我要给大家分享一些关于爬虫ip池的知识。关于ip代理池的问题,答案是肯定的,池子越大越好。下面跟我一起来盘点一下ip池大的好处吧! 1、提高稳定性 爬虫ip池越大,意味着拥有更多可用的爬虫ip…...

目标检测常用的数据集格式

在目标检测领域,有三种常用的数据集: 数据集标注文件格式bbox格式vocxmlxmin, ymin, xmax, ymax:bbox左上角(xmin, ymin)和右下角(xmax, ymax)的坐标cocojsonx, y, w, h:bbox左上角坐标(x, y)以及宽(w)和高(h)yolotxtxcenter, ycenter, w, h:bbox的中心…...

chrome插件开发实例03-使用 chrome.storage API永久保存数据

目录 防止数据丢失 使用chrome.storage API 功能 功能演示 源代码 manifest.json popup.html...

Segment Anything(SAM) 计算过程

给定输入图像 I ∈ R 3 H W I \in R^{3 \times H \times W} I∈R3HW。给定需要的prompts: M ∈ R 1 H W M \in R^{1 \times H \times W} M∈R1HW,代表图片的前背景信息。 P ∈ R N 2 P \in R^{N \times 2} P∈RN2,其中 N N N 是点的个数…...

Nacos配置文件读取源码解析

Nacos配置文件读取 本篇文章是探究,springboot启动时nacos是如何将配置中心的配置读取到springboot环境中的 PropertySourceLocator org.springframework.cloud.bootstrap.config.PropertySourceLocator 是 springcloud 定义的一个顶级接口,用来定义所…...

Linux0.11内核源码解析-fcntl.c/iotcl.c/stat.c

fcntl fcntl.c实现了文件控制系统调用fcntl和两个文件句柄描述符的复制系统调用dup()和dup2()。 dup返回当前值最小的未用句柄,dup2返回指定新句柄的数值,句柄的复制操作主要用在文件的标准输入、输出重定向和管道方面。 dupfd 复制文件句柄&#xff…...

OpenStack简介

OpenStack简介 目录 OpenStack简介 1、云计算模式2、云计算 虚拟化 openstack之间的关系?3、OpenStack 中有哪些组件?4、计算节点负责虚拟机运行5、网络节点负责对外网络与内网之间的通信 5.1 网络节点仅包含Neutron服务5.2 网络节点包含三个网络端口6、…...

二分法的应用

文章目录 什么是二分法🎮二分查找的优先级二分查找的步骤💥图解演示🧩 代码演示🫕python程序实现🐈‍⬛C程序实现🐕‍🦺C程序实现🐯Java程序实现🐳 非常规类二分查找&…...

ChatGPT在大规模数据处理和信息管理中的应用如何?

ChatGPT作为一种强大的自然语言处理模型,在大规模数据处理和信息管理领域有着广泛的应用潜力。它可以利用其文本生成、文本理解和问答等能力,为数据分析、信息提取、知识管理等任务提供智能化的解决方案。以下将详细介绍ChatGPT在大规模数据处理和信息管…...

【算法篇C++实现】五大常规算法

文章目录 🚀一、分治法⛳(一)算法思想⛳(二)相关代码 🚀二、动态规划算法⛳(一)算法思想⛳(二)相关代码 🚀三、回溯算法⛳(一&#xf…...

MySQL和钉钉单据接口对接

MySQL和钉钉单据接口对接 数据源系统:钉钉 钉钉(DingTalk)是阿里巴巴集团打造的企业级智能移动办公平台,是数字经济时代的企业组织协同办公和应用开发平台。钉钉将IM即时沟通、钉钉文档、钉闪会、钉盘、Teambition、OA审批、智能人事、钉工牌…...

layui的基本使用-日期控件的业务场景使用入门实战案例一

效果镇楼&#xff1b; 1 前端UI层面&#xff1b; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport&…...

【2.1】Java微服务:详解Hystrix

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; Java微服务 ✨特色专栏&#xff1a; 知识分享 &am…...

Apache2.4源码安装与配置

环境准备 openssl-devel pcre-devel expat-devel libtool gcc libxml2-devel 这些包要提前安装&#xff0c;否则httpd编译安装时候会报错 下载源码、解压缩、软连接 1、wget下载[rootnode01 ~]# wget https://downloads.apache.org/httpd/httpd-2.4.57.tar.gz --2023-07-20 …...

Flume原理剖析

一、介绍 Flume是一个高可用、高可靠&#xff0c;分布式的海量日志采集、聚合和传输的系统。Flume支持在日志系统中定制各类数据发送方&#xff0c;用于收集数据&#xff1b;同时&#xff0c;Flume提供对数据进行简单处理&#xff0c;并写到各种数据接受方&#xff08;可定制&…...

【leetcode】202. 快乐数(easy)

编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。如果这个过程 结果为 1&#xff0c…...

如何用瀑布图分析公司年报

原创&#xff1a; MicroStrategy微策略中国 , Jiping Sun 微策略企业级数据分析与移动应用9月21日2018年 摘要&#xff1a;利用达析报告开箱即用的瀑布图来展示各个度量值如何增加或减少。下载MicroStrategy Desktop 10.11以上版本&#xff0c;自己动手创建瀑布图。 瀑布图是由…...

Asynq: 基于Redis实现的Go生态分布式任务队列和异步处理库

Asynq[1]是一个Go实现的分布式任务队列和异步处理库&#xff0c;基于redis&#xff0c;类似Ruby的sidekiq[2]和Python的celery[3]。Go生态类似的还有machinery[4]和goworker 同时提供一个WebUI asynqmon[5]&#xff0c;可以源码形式安装或使用Docker image, 还可以和Prometheus…...

保证率计算公式 正态分布

在正态分布中&#xff0c;如果我们要计算一个给定区间内的保证率&#xff0c;可以使用下面的计算公式&#xff1a; 找到给定保证率对应的标准正态分布的z值。可以使用标准正态分布表或计算器进行查询。例如&#xff0c;对于95%的保证率&#xff0c;对应的z值为1.96。 使用z值和…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...