Java特性之设计模式【代理模式】

一、代理模式

概述

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式

在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口

主要解决

在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层

何时使用

想在访问一个类时做一些控制

优缺点

优点:

  • 职责清晰
  • 高扩展性
  • 智能化

缺点:

  • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢
  • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂

注意事项

  • 和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口
  • 和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制

1. 各个角色介绍

1.1 抽象主题(Subject)

  • 定义了真实主题和代理主题的共同接口,这样在任何使用真实主题的地方都可以使用代理主题

1.2 真实主题(Real Subject)

  • 实现了抽象主题接口,是代理对象所代表的真实对象。客户端直接访问真实主题,但在某些情况下,可以通过代理主题来间接访问

1.3 代理(Proxy)

  • 实现了抽象主题接口,并持有对真实主题的引用。代理主题通常在真实主题的基础上提供一些额外的功能,例如延迟加载、权限控制、日志记录等

2. UML图

​ 我们将创建一个 ILandlordService 租房接口和实现了 ILandlordService 接口的实体类。AgentProxy 是一个代理类,减少房东 HostServiceImpl 对象加载的内存占用

在这里插入图片描述

3. 具体例子和代码

角色分配

  • ILandlordService:租房接口
    • HostServiceImpl:房东实现类
    • AgentProxy:中介代理

3.1 租房接口及其实现类

  • ILandlordService
package com.vinjcent.prototype.proxy;/*** @author vinjcent* @description 租房接口* @since 2024/3/27 17:52*/
public interface ILandlordService {/*** 出租** @param money 金额*/void rent(Integer money);}
  • HostServiceImpl
package com.vinjcent.prototype.proxy;/*** @author vinjcent* @description 房东实现类(实现)* @since 2024/3/27 17:55*/
public class HostServiceImpl implements ILandlordService {@Overridepublic void rent(Integer money) {System.out.println("房东处理...");System.out.println("出租" + money + "元一个月的房子");}@Overridepublic String toString() {return "HostServiceImpl{}";}
}
  • AgentProxy
package com.vinjcent.prototype.proxy.static_proxy;import com.vinjcent.prototype.proxy.HostServiceImpl;
import com.vinjcent.prototype.proxy.ILandlordService;/*** @author vinjcent* @description 中介代理* @since 2024/3/27 18:04*/
public class AgentProxy implements ILandlordService {/*** 被代理的对象*/private ILandlordService target;@Overridepublic void rent(Integer money) {if (target == null) {target = new HostServiceImpl();}System.out.println("中介处理...");target.rent(money);}
}

3.2 额外拓展(动态代理:JDK动态代理、CGLib动态代理)

3.2.1 JDK动态代理

JDK动态代理的代理类根据目标实现的接口动态生成,不需要自己编写,生成的动态代理类和目标类都实现相同的接口,JDK动态代理的核心是InvocationHandler接口和Proxy类,缺点是目标类必须有实现接口,如果某个目标类没有实现接口,那么这个类就不能用JDK动态代理

  • JDKProxyFactory
package com.vinjcent.prototype.proxy.dynamic_proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @author vinjcent* @description JDK动态代理* @since 2024/3/27 17:24*/
public class JDKProxyFactory implements InvocationHandler {/*** 需要被代理的对象*/private final Object object;public JDKProxyFactory(Object object) {this.object = object;}@SuppressWarnings("unchecked")public <T> T getProxy() {Object o = Proxy.newProxyInstance(// 当前线程的上下文ClassLoaderThread.currentThread().getContextClassLoader(),// 代理对象实现的接口this.object.getClass().getInterfaces(),// 处理器自身this);return (T) o;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = new Object();// 进行方法匹配,调用对应方法名的方法if ("rent".equals(method.getName())) {System.out.println("JDK动态代理前置增强");result = method.invoke(object, args);System.out.println("JDK动态代理后置增强");}return result;}@Overridepublic String toString() {return "JDKProxyFactory{" +"object=" + object +'}';}
}
3.2.2 CGLib动态代理

在程序运行时动态生成类的字节码,动态创建目标类的子类对象,在子类对象中增强目标类,CGLib是通过继承的方式实现的动态代理,因此如果某个类被标记为final,它是无法使用CGLib做动态代理的,优点在于不需要实现特定的接口,更加灵活

在这里插入图片描述

  • CglibProxyFactory
package com.vinjcent.prototype.proxy.dynamic_proxy;import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** @author vinjcent* @description CGLib动态代理* @since 2024/3/27 22:42:16*/
public class CglibProxyFactory implements MethodInterceptor {@SuppressWarnings("unchecked")public <T> T getProxy(Class<T> clazz) {// Enhancer是CGLIB库中用于动态生成子类的主要类.通过创建Enhancer对象并设置需要代理的目标类、拦截器等参数,可以生成一个代理类Enhancer en = new Enhancer();// 设置代理的父类en.setSuperclass(clazz);// 设置方法回调en.setCallback(this);Object o = en.create();// 创建代理实例.通过调用Enhancer对象的create方法,可以生成一个代理对象.代理对象会继承目标类的方法,并且在调用代理对象的方法时会先调用拦截器的intercept方法,再执行目标方法return (T) en.create();}@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {// 在生成代理类时,需要指定拦截器.拦截器是实现代理逻辑的关键,它会在代理类的方法被调用时拦截调用,并执行相应的逻辑Object result = null;System.out.println("CGLIB动态代理前置增强");// 通过调用代理对象的方法,会触发拦截器的intercept方法.在intercept方法中,可以根据需要执行各种逻辑,比如添加日志、性能统计、事务管理等if ("rent".equals(method.getName())) {// 通过继承的方法实现代理,因此这里调用invokeSuperresult = methodProxy.invokeSuper(o, args);}System.out.println("CGLIB动态代理后置增强");return result;}
}

3.3 测试主函数

package com.vinjcent.prototype.proxy;import com.vinjcent.prototype.proxy.dynamic_proxy.CglibProxyFactory;
import com.vinjcent.prototype.proxy.dynamic_proxy.JDKProxyFactory;
import com.vinjcent.prototype.proxy.static_proxy.AgentProxy;/*** @author vinjcent* @description 代理模式* @since 2024/3/27 18:01*/
public class Main {public static void main(String[] args) {System.out.println("静态代理");// 静态代理ILandlordService landlordService = new AgentProxy();System.out.println("第一次代理调用目标类方法");landlordService.rent(20);System.out.println("\n第二次代理调用目标类的方法");landlordService.rent(25);System.out.println("\n");HostServiceImpl hostService = new HostServiceImpl();System.out.println("JDK动态代理");// JDK动态代理ILandlordService jdkProxy = new JDKProxyFactory(hostService).getProxy();jdkProxy.rent(750);System.out.println("\n");System.out.println("CGLib动态代理");// CGLIB动态代理HostServiceImpl cglibProxy = new CglibProxyFactory().getProxy(hostService.getClass());cglibProxy.rent(750);}}
  • 测试结果

在这里插入图片描述

4. 使用场景

  • 远程代理
  • 虚拟代理
  • Copy-on-Write 代理
  • 保护(Protect or Access)代理
  • Cache代理
  • 防火墙(Firewall)代理
  • 同步化(Synchronization)代理
  • 智能引用(Smart Reference)代理

在这里插入图片描述

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

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

相关文章

DenseCLIP环境配置

直接看raoyongming/DenseCLIP: [CVPR 2022] DenseCLIP: Language-Guided Dense Prediction with Context-Aware Prompting (github.com) 但这里的环境配置可能和现在不太适配&#xff0c;自己配了好久没弄好 后面尝试了另外的版本的&#xff08;但这个版本少了一些内容&#…

五种算法(BWO、RUN、SO、HO、GWO)求解复杂城市地形下无人机路径规划,可以修改障碍物及起始点(MATLAB)

一、算法介绍 &#xff08;1&#xff09;白鲸优化算法BWO 参考文献&#xff1a;Zhong C, Li G, Meng Z. Beluga whale optimization: A novel nature-inspired metaheuristic algorithm[J]. Knowledge-Based Systems, 2022, 109215. &#xff08;2&#xff09;龙格-库塔优化…

高精度数学计算的瑞士军刀,mpmath库详解与应用示例

写在前言 hello&#xff0c;大家好&#xff0c;我是一点&#xff0c;专注于Python编程&#xff0c;如果你也对感Python感兴趣&#xff0c;欢迎关注交流。 做为一个一只脚已经踏进35岁大关的程序员&#xff0c;对于职场&#xff0c;几乎向上无望&#xff0c;已经没有太多的期待…

案例分享:BACnet转Modbus提升暖通系统互操作性

现代智能建筑中系统的集成与互操作性是决定其智能化程度的关键因素。随着技术的发展&#xff0c;不同标准下的设备共存成为常态&#xff0c;而BACnet与Modbus作为楼宇自动化领域广泛采用的通讯协议&#xff0c;它们之间的无缝对接显得尤为重要。本文将通过一个实际案例&#xf…

二叉树的前序、中序、后序遍历的C++实现

二叉树的前序、中序、后序 遍历属于深度优先搜索方式&#xff0c;本文使用递归法实现前序、中序、后序的遍历方法&#xff0c;代码如下&#xff1a; #include <iostream> #include <vector>struct TreeNode{int val;TreeNode* left;TreeNode* right;TreeNode(int …

DeepSeek API文档:创建对话补全的指南

DeepSeek平台不仅提供了一个用户友好的聊天界面&#xff0c;还为开发者提供了强大的API接口&#xff0c;使他们能够创建和集成智能对话补全功能。以下是关于如何使用DeepSeek API创建对话补全的详细介绍。 DeepSeek API概述 DeepSeek的API允许开发者通过编程方式与DeepSeek的…

分布式与一致性协议之ZAB协议(八)

ZAB协议 如何实现读操作 相比写操作&#xff0c;读操作的处理要简单很多&#xff0c;因为接收到度请求的节点只需要查询本地数据&#xff0c;然后响应数据给客户端就可以了。读操作的核心流程如图所示。 1.跟随者在FollowerRequestProcessor.processRequest()中接收到度请求…

双向BFS算法学习

双向BFS算法学习 推荐练习题 力扣“127”题&#xff1a;单词接龙 “752”题&#xff1a;打开轮盘锁 这里推荐一篇力扣题解 双向BFS 这里使用打开轮盘锁的题干进行举例&#xff1a; 你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字&#xff1a; ‘0’, ‘1’, ‘2’,…

数据结构(链表)

文章目录 1.单链表1.基本介绍1.定义2.逻辑结构 2.应用实例1.需求分析2.思路分析3.完成添加和显示链表信息&#xff0c;直接添加到链表的尾部4.根据排名添加&#xff0c;如果排名重复则给出提示5.根据新节点的编号来修改信息6.删除指定id的节点 3.单链表面试题1.题目2.面试题一2…

搜狗输入法 PC端 v14.4.0.9307 去广告绿化版.

软件介绍 搜狗拼音输入法作为众多用户计算机配置的必备工具&#xff0c;其功能的全面性已为众所周知&#xff0c;并且以其高效便捷的输入体验受到广大使用者的青睐。然而&#xff0c;该软件在提供便利的同时&#xff0c;其内置的广告元素常常为用户带来一定的干扰。为此&#…

基于Nios-II的流水灯

基于Nios-II的流水灯 一、Qsys设计&#xff08;一&#xff09;新建项目&#xff08;二&#xff09;Platfrom Designer&#xff08;三&#xff09;设置时钟主频&#xff08;四&#xff09;添加Nios-II Processor并设置&#xff08;五&#xff09;添加JTAG并配置&#xff08;六&a…

win11更新过后偶尔出现网卡详细信息为空

鼠标右键网卡属性&#xff0c;看下是不是多了一个Network LightWeight Filter 前面对号取消然后确定就能获取到IP了 详情请自行查看百度文库